• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
15 #include "Coroutine.hpp"
16 #include "Print.hpp"
17 #include "Reactor.hpp"
18 
19 #include "gtest/gtest.h"
20 
21 #include <array>
22 #include <cmath>
23 #include <filesystem>
24 #include <fstream>
25 #include <thread>
26 #include <tuple>
27 
28 using namespace rr;
29 
testName()30 static std::string testName()
31 {
32 	auto info = ::testing::UnitTest::GetInstance()->current_test_info();
33 	return std::string{ info->test_suite_name() } + "_" + info->name();
34 }
35 
reference(int * p,int y)36 int reference(int *p, int y)
37 {
38 	int x = p[-1];
39 	int z = 4;
40 
41 	for(int i = 0; i < 10; i++)
42 	{
43 		z += (2 << i) - (i / 3);
44 	}
45 
46 	int sum = x + y + z;
47 
48 	return sum;
49 }
50 
TEST(ReactorUnitTests,Sample)51 TEST(ReactorUnitTests, Sample)
52 {
53 	FunctionT<int(int *, int)> function;
54 	{
55 		Pointer<Int> p = function.Arg<0>();
56 		Int x = p[-1];
57 		Int y = function.Arg<1>();
58 		Int z = 4;
59 
60 		For(Int i = 0, i < 10, i++)
61 		{
62 			z += (2 << i) - (i / 3);
63 		}
64 
65 		Float4 v;
66 		v.z = As<Float>(z);
67 		z = As<Int>(Float(Float4(v.xzxx).y));
68 
69 		Int sum = x + y + z;
70 
71 		Return(sum);
72 	}
73 
74 	auto routine = function(testName().c_str());
75 
76 	int one[2] = { 1, 0 };
77 	int result = routine(&one[1], 2);
78 	EXPECT_EQ(result, reference(&one[1], 2));
79 }
80 
81 // This test demonstrates the use of a 'trampoline', where a routine calls
82 // a static function which then generates another routine during the execution
83 // of the first routine. Also note the code generated for the second routine
84 // depends on a parameter passed to the first routine.
TEST(ReactorUnitTests,Trampoline)85 TEST(ReactorUnitTests, Trampoline)
86 {
87 	using SecondaryFunc = int(int, int);
88 
89 	static auto generateSecondary = [](int upDown) {
90 		FunctionT<SecondaryFunc> secondary;
91 		{
92 			Int x = secondary.Arg<0>();
93 			Int y = secondary.Arg<1>();
94 			Int r;
95 
96 			if(upDown > 0)
97 			{
98 				r = x + y;
99 			}
100 			else if(upDown < 0)
101 			{
102 				r = x - y;
103 			}
104 			else
105 			{
106 				r = 0;
107 			}
108 
109 			Return(r);
110 		}
111 
112 		static auto routine = secondary((testName() + "_secondary").c_str());
113 		return routine.getEntry();
114 	};
115 
116 	using SecondaryGeneratorFunc = SecondaryFunc *(*)(int);
117 	SecondaryGeneratorFunc secondaryGenerator = (SecondaryGeneratorFunc)generateSecondary;
118 
119 	using PrimaryFunc = int(int, int, int);
120 
121 	FunctionT<PrimaryFunc> primary;
122 	{
123 		Int x = primary.Arg<0>();
124 		Int y = primary.Arg<1>();
125 		Int z = primary.Arg<2>();
126 
127 		Pointer<Byte> secondary = Call(secondaryGenerator, z);
128 		Int r = Call<SecondaryFunc>(secondary, x, y);
129 
130 		Return(r);
131 	}
132 
133 	auto routine = primary((testName() + "_primary").c_str());
134 
135 	int result = routine(100, 20, -3);
136 	EXPECT_EQ(result, 80);
137 }
138 
TEST(ReactorUnitTests,Uninitialized)139 TEST(ReactorUnitTests, Uninitialized)
140 {
141 	FunctionT<int()> function;
142 	{
143 		Int a;
144 		Int z = 4;
145 		Int q;
146 		Int c;
147 		Int p;
148 		Bool b;
149 
150 		q += q;
151 
152 		If(b)
153 		{
154 			c = p;
155 		}
156 
157 		Return(a + z + q + c);
158 	}
159 
160 	auto routine = function(testName().c_str());
161 
162 	if(!__has_feature(memory_sanitizer) || !REACTOR_ENABLE_MEMORY_SANITIZER_INSTRUMENTATION)
163 	{
164 		int result = routine();
165 		EXPECT_EQ(result, result);  // Anything is fine, just don't crash
166 	}
167 	else
168 	{
169 		// Optimizations may turn the conditional If() in the Reactor code
170 		// into a conditional move or arithmetic operations, which would not
171 		// trigger a MemorySanitizer error. However, in that case the equals
172 		// operator below should trigger it before the abort is reached.
173 		EXPECT_DEATH(
174 		    {
175 			    int result = routine();
176 			    if(result == 0) abort();
177 		    },
178 		    "MemorySanitizer: use-of-uninitialized-value");
179 	}
180 }
181 
TEST(ReactorUnitTests,Unreachable)182 TEST(ReactorUnitTests, Unreachable)
183 {
184 	FunctionT<int(int)> function;
185 	{
186 		Int a = function.Arg<0>();
187 		Int z = 4;
188 
189 		Return(a + z);
190 
191 		// Code beyond this point is unreachable but should not cause any
192 		// compilation issues.
193 
194 		z += a;
195 	}
196 
197 	auto routine = function(testName().c_str());
198 
199 	int result = routine(16);
200 	EXPECT_EQ(result, 20);
201 }
202 
203 // Stopping in the middle of a `Function<>` is supported and should not affect
204 // subsequent complete ones.
TEST(ReactorUnitTests,UnfinishedFunction)205 TEST(ReactorUnitTests, UnfinishedFunction)
206 {
207 	do
208 	{
209 		FunctionT<int(int)> function;
210 		{
211 			Int a = function.Arg<0>();
212 			Int z = 4;
213 
214 			if((true)) break;  // Terminate do-while early.
215 
216 			Return(a + z);
217 		}
218 	} while(true);
219 
220 	FunctionT<int(int)> function;
221 	{
222 		Int a = function.Arg<0>();
223 		Int z = 4;
224 
225 		Return(a - z);
226 	}
227 
228 	auto routine = function(testName().c_str());
229 
230 	int result = routine(16);
231 	EXPECT_EQ(result, 12);
232 }
233 
234 // Deriving from `Function<>` and using Reactor variables as members can be a
235 // convenient way to 'name' function arguments and compose complex functions
236 // with helper methods. This test checks the interactions between the lifetime
237 // of the `Function<>` and the variables belonging to the derived class.
238 struct FunctionMembers : FunctionT<int(int)>
239 {
FunctionMembersFunctionMembers240 	FunctionMembers()
241 	    : level(Arg<0>())
242 	{
243 		For(Int i = 0, i < 3, i++)
244 		{
245 			pourSomeMore();
246 		}
247 
248 		Return(level);
249 	}
250 
pourSomeMoreFunctionMembers251 	void pourSomeMore()
252 	{
253 		level += 2;
254 	}
255 
256 	Int level;
257 };
258 
TEST(ReactorUnitTests,FunctionMembers)259 TEST(ReactorUnitTests, FunctionMembers)
260 {
261 	FunctionMembers function;
262 
263 	auto routine = function(testName().c_str());
264 
265 	int result = routine(3);
266 	EXPECT_EQ(result, 9);
267 }
268 
269 // This test excercises modifying the value of a local variable through a
270 // pointer to it.
TEST(ReactorUnitTests,VariableAddress)271 TEST(ReactorUnitTests, VariableAddress)
272 {
273 	FunctionT<int(int)> function;
274 	{
275 		Int a = function.Arg<0>();
276 		Int z = 0;
277 		Pointer<Int> p = &z;
278 		*p = 4;
279 
280 		Return(a + z);
281 	}
282 
283 	auto routine = function(testName().c_str());
284 
285 	int result = routine(16);
286 	EXPECT_EQ(result, 20);
287 }
288 
289 // This test exercises taking the address of a local varible at the end of a
290 // loop and modifying its value through the pointer in the second iteration.
TEST(ReactorUnitTests,LateVariableAddress)291 TEST(ReactorUnitTests, LateVariableAddress)
292 {
293 	FunctionT<int(void)> function;
294 	{
295 		Pointer<Int> p = nullptr;
296 		Int a = 0;
297 
298 		While(a == 0)
299 		{
300 			If(p != Pointer<Int>(nullptr))
301 			{
302 				*p = 1;
303 			}
304 
305 			p = &a;
306 		}
307 
308 		Return(a);
309 	}
310 
311 	auto routine = function(testName().c_str());
312 
313 	int result = routine();
314 	EXPECT_EQ(result, 1);
315 }
316 
317 // This test checks that the value of a local variable which has been modified
318 // though a pointer is correct at the point before its address is (statically)
319 // obtained.
TEST(ReactorUnitTests,LoadAfterIndirectStore)320 TEST(ReactorUnitTests, LoadAfterIndirectStore)
321 {
322 	FunctionT<int(void)> function;
323 	{
324 		Pointer<Int> p = nullptr;
325 		Int a = 0;
326 		Int b = 0;
327 
328 		While(a == 0)
329 		{
330 			If(p != Pointer<Int>(nullptr))
331 			{
332 				*p = 1;
333 			}
334 
335 			// `a` must be loaded from memory here, despite not statically knowing
336 			// yet that its address will be taken below.
337 			b = a + 5;
338 
339 			p = &a;
340 		}
341 
342 		Return(b);
343 	}
344 
345 	auto routine = function(testName().c_str());
346 
347 	int result = routine();
348 	EXPECT_EQ(result, 6);
349 }
350 
351 // This test checks that variables statically accessed after a Return statement
352 // are still loaded, modified, and stored correctly.
TEST(ReactorUnitTests,LoopAfterReturn)353 TEST(ReactorUnitTests, LoopAfterReturn)
354 {
355 	FunctionT<int(void)> function;
356 	{
357 		Int min = 100;
358 		Int max = 200;
359 
360 		If(min > max)
361 		{
362 			Return(5);
363 		}
364 
365 		While(min < max)
366 		{
367 			min++;
368 		}
369 
370 		Return(7);
371 	}
372 
373 	auto routine = function(testName().c_str());
374 
375 	int result = routine();
376 	EXPECT_EQ(result, 7);
377 }
378 
TEST(ReactorUnitTests,ConstantPointer)379 TEST(ReactorUnitTests, ConstantPointer)
380 {
381 	int c = 44;
382 
383 	FunctionT<int()> function;
384 	{
385 		Int x = *Pointer<Int>(ConstantPointer(&c));
386 
387 		Return(x);
388 	}
389 
390 	auto routine = function(testName().c_str());
391 
392 	int result = routine();
393 	EXPECT_EQ(result, 44);
394 }
395 
396 // This test excercises the Optimizer::eliminateLoadsFollowingSingleStore() optimization pass.
397 // The three load operations for `y` should get eliminated.
TEST(ReactorUnitTests,EliminateLoadsFollowingSingleStore)398 TEST(ReactorUnitTests, EliminateLoadsFollowingSingleStore)
399 {
400 	FunctionT<int(int)> function;
401 	{
402 		Int x = function.Arg<0>();
403 
404 		Int y;
405 		Int z;
406 
407 		// This branch materializes the variables.
408 		If(x != 0)  // TODO(b/179922668): Support If(x)
409 		{
410 			y = x;
411 			z = y + y + y;
412 		}
413 
414 		Return(z);
415 	}
416 
417 	Nucleus::setOptimizerCallback([](const Nucleus::OptimizerReport *report) {
418 		EXPECT_EQ(report->allocas, 2);
419 		EXPECT_EQ(report->loads, 2);
420 		EXPECT_EQ(report->stores, 2);
421 	});
422 
423 	auto routine = function(testName().c_str());
424 
425 	int result = routine(11);
426 	EXPECT_EQ(result, 33);
427 }
428 
429 // This test excercises the Optimizer::propagateAlloca() optimization pass.
430 // The pointer variable should not get stored to / loaded from memory.
TEST(ReactorUnitTests,PropagateAlloca)431 TEST(ReactorUnitTests, PropagateAlloca)
432 {
433 	FunctionT<int(int)> function;
434 	{
435 		Int b = function.Arg<0>();
436 
437 		Int a = 22;
438 		Pointer<Int> p;
439 
440 		// This branch materializes both `a` and `p`, and ensures single basic block
441 		// optimizations don't also eliminate the pointer store and load.
442 		If(b != 0)  // TODO(b/179922668): Support If(b)
443 		{
444 			p = &a;
445 		}
446 
447 		Return(Int(*p));  // TODO(b/179694472): Support Return(*p)
448 	}
449 
450 	Nucleus::setOptimizerCallback([](const Nucleus::OptimizerReport *report) {
451 		EXPECT_EQ(report->allocas, 1);
452 		EXPECT_EQ(report->loads, 1);
453 		EXPECT_EQ(report->stores, 1);
454 	});
455 
456 	auto routine = function(testName().c_str());
457 
458 	int result = routine(true);
459 	EXPECT_EQ(result, 22);
460 }
461 
462 // Corner case for Optimizer::propagateAlloca(). It should not replace loading of `p`
463 // with the addres of `a`, since it also got the address of `b` assigned.
TEST(ReactorUnitTests,PointerToPointer)464 TEST(ReactorUnitTests, PointerToPointer)
465 {
466 	FunctionT<int()> function;
467 	{
468 		Int a = 444;
469 		Int b = 555;
470 
471 		Pointer<Int> p = &a;
472 		Pointer<Pointer<Int>> pp = &p;
473 		p = &b;
474 
475 		Return(Int(*Pointer<Int>(*pp)));  // TODO(b/179694472): Support **pp
476 	}
477 
478 	auto routine = function(testName().c_str());
479 
480 	int result = routine();
481 	EXPECT_EQ(result, 555);
482 }
483 
484 // Corner case for Optimizer::propagateAlloca(). It should not replace loading of `p[i]`
485 // with any of the addresses of the `a`, `b`, or `c`.
TEST(ReactorUnitTests,ArrayOfPointersToLocals)486 TEST(ReactorUnitTests, ArrayOfPointersToLocals)
487 {
488 	FunctionT<int(int)> function;
489 	{
490 		Int i = function.Arg<0>();
491 
492 		Int a = 111;
493 		Int b = 222;
494 		Int c = 333;
495 
496 		Array<Pointer<Int>, 3> p;
497 		p[0] = &a;
498 		p[1] = &b;
499 		p[2] = &c;
500 
501 		Return(Int(*Pointer<Int>(p[i])));  // TODO(b/179694472): Support *p[i]
502 	}
503 
504 	auto routine = function(testName().c_str());
505 
506 	int result = routine(1);
507 	EXPECT_EQ(result, 222);
508 }
509 
TEST(ReactorUnitTests,ModifyLocalThroughPointer)510 TEST(ReactorUnitTests, ModifyLocalThroughPointer)
511 {
512 	FunctionT<int(void)> function;
513 	{
514 		Int a = 1;
515 
516 		Pointer<Int> p = &a;
517 		Pointer<Pointer<Int>> pp = &p;
518 
519 		Pointer<Int> q = *pp;
520 		*q = 3;
521 
522 		Return(a);
523 	}
524 
525 	auto routine = function(testName().c_str());
526 
527 	int result = routine();
528 	EXPECT_EQ(result, 3);
529 }
530 
TEST(ReactorUnitTests,ScalarReplacementOfArray)531 TEST(ReactorUnitTests, ScalarReplacementOfArray)
532 {
533 	FunctionT<int(void)> function;
534 	{
535 		Array<Int, 2> a;
536 		a[0] = 1;
537 		a[1] = 2;
538 
539 		Return(a[0] + a[1]);
540 	}
541 
542 	auto routine = function(testName().c_str());
543 
544 	int result = routine();
545 	EXPECT_EQ(result, 3);
546 }
547 
TEST(ReactorUnitTests,CArray)548 TEST(ReactorUnitTests, CArray)
549 {
550 	FunctionT<int(void)> function;
551 	{
552 		Int a[2];
553 		a[0] = 1;
554 		a[1] = 2;
555 
556 		auto x = a[0];
557 		a[0] = a[1];
558 		a[1] = x;
559 
560 		Return(a[0] + a[1]);
561 	}
562 
563 	auto routine = function(testName().c_str());
564 
565 	int result = routine();
566 	EXPECT_EQ(result, 3);
567 }
568 
569 // SRoA should replace the array elements with scalars, which in turn enables
570 // eliminating all loads and stores.
TEST(ReactorUnitTests,ReactorArray)571 TEST(ReactorUnitTests, ReactorArray)
572 {
573 	FunctionT<int(void)> function;
574 	{
575 		Array<Int, 2> a;
576 		a[0] = 1;
577 		a[1] = 2;
578 
579 		Int x = a[0];
580 		a[0] = a[1];
581 		a[1] = x;
582 
583 		Return(a[0] + a[1]);
584 	}
585 
586 	Nucleus::setOptimizerCallback([](const Nucleus::OptimizerReport *report) {
587 		EXPECT_EQ(report->allocas, 0);
588 		EXPECT_EQ(report->loads, 0);
589 		EXPECT_EQ(report->stores, 0);
590 	});
591 
592 	auto routine = function(testName().c_str());
593 
594 	int result = routine();
595 	EXPECT_EQ(result, 3);
596 }
597 
598 // Excercises the optimizeSingleBasicBlockLoadsStores optimization pass.
TEST(ReactorUnitTests,StoresInMultipleBlocks)599 TEST(ReactorUnitTests, StoresInMultipleBlocks)
600 {
601 	FunctionT<int(int)> function;
602 	{
603 		Int b = function.Arg<0>();
604 
605 		Int a = 13;
606 
607 		If(b != 0)  // TODO(b/179922668): Support If(b)
608 		{
609 			a = 4;
610 			a = a + 3;
611 		}
612 		Else
613 		{
614 			a = 6;
615 			a = a + 5;
616 		}
617 
618 		Return(a);
619 	}
620 
621 	Nucleus::setOptimizerCallback([](const Nucleus::OptimizerReport *report) {
622 		EXPECT_EQ(report->allocas, 1);
623 		EXPECT_EQ(report->loads, 1);
624 		EXPECT_EQ(report->stores, 3);
625 	});
626 
627 	auto routine = function(testName().c_str());
628 
629 	int result = routine(true);
630 	EXPECT_EQ(result, 7);
631 }
632 
633 // This is similar to the LoadAfterIndirectStore test except that the indirect
634 // store is preceded by a direct store. The subsequent load should not be replaced
635 // by the value written by the direct store.
TEST(ReactorUnitTests,StoreBeforeIndirectStore)636 TEST(ReactorUnitTests, StoreBeforeIndirectStore)
637 {
638 	FunctionT<int(int)> function;
639 	{
640 		//Int b = function.Arg<0>();
641 
642 		Int b;
643 		Pointer<Int> p = &b;
644 		Int a = 13;
645 
646 		For(Int i = 0, i < 2, i++)
647 		{
648 			a = 10;
649 
650 			*p = 4;
651 
652 			// This load of `a` should not be replaced by the 10 written above, since
653 			// in the second iteration `p` points to `a` and writes 4.
654 			b = a;
655 
656 			p = &a;
657 		}
658 
659 		Return(b);
660 	}
661 
662 	auto routine = function(testName().c_str());
663 
664 	int result = routine(true);
665 	EXPECT_EQ(result, 4);
666 }
667 
TEST(ReactorUnitTests,SubVectorLoadStore)668 TEST(ReactorUnitTests, SubVectorLoadStore)
669 {
670 	FunctionT<int(void *, void *)> function;
671 	{
672 		Pointer<Byte> in = function.Arg<0>();
673 		Pointer<Byte> out = function.Arg<1>();
674 
675 		*Pointer<Int4>(out + 16 * 0) = *Pointer<Int4>(in + 16 * 0);
676 		*Pointer<Short4>(out + 16 * 1) = *Pointer<Short4>(in + 16 * 1);
677 		*Pointer<Byte8>(out + 16 * 2) = *Pointer<Byte8>(in + 16 * 2);
678 		*Pointer<Byte4>(out + 16 * 3) = *Pointer<Byte4>(in + 16 * 3);
679 		*Pointer<Short2>(out + 16 * 4) = *Pointer<Short2>(in + 16 * 4);
680 
681 		Return(0);
682 	}
683 
684 	auto routine = function(testName().c_str());
685 
686 	int8_t in[16 * 5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
687 		                  17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0,
688 		                  25, 26, 27, 28, 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 0,
689 		                  33, 34, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
690 		                  37, 38, 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
691 
692 	int8_t out[16 * 5] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
693 		                   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
694 		                   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
695 		                   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
696 		                   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
697 
698 	routine(in, out);
699 
700 	for(int row = 0; row < 5; row++)
701 	{
702 		for(int col = 0; col < 16; col++)
703 		{
704 			int i = row * 16 + col;
705 
706 			if(in[i] == 0)
707 			{
708 				EXPECT_EQ(out[i], -1) << "Row " << row << " column " << col << " not left untouched.";
709 			}
710 			else
711 			{
712 				EXPECT_EQ(out[i], in[i]) << "Row " << row << " column " << col << " not equal to input.";
713 			}
714 		}
715 	}
716 }
717 
TEST(ReactorUnitTests,VectorConstant)718 TEST(ReactorUnitTests, VectorConstant)
719 {
720 	FunctionT<int(void *)> function;
721 	{
722 		Pointer<Byte> out = function.Arg<0>();
723 
724 		*Pointer<Int4>(out + 16 * 0) = Int4(0x04030201, 0x08070605, 0x0C0B0A09, 0x100F0E0D);
725 		*Pointer<Short4>(out + 16 * 1) = Short4(0x1211, 0x1413, 0x1615, 0x1817);
726 		*Pointer<Byte8>(out + 16 * 2) = Byte8(0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20);
727 		*Pointer<Int2>(out + 16 * 3) = Int2(0x24232221, 0x28272625);
728 
729 		Return(0);
730 	}
731 
732 	auto routine = function(testName().c_str());
733 
734 	int8_t out[16 * 4] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
735 		                   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
736 		                   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
737 		                   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
738 
739 	int8_t exp[16 * 4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
740 		                   17, 18, 19, 20, 21, 22, 23, 24, -1, -1, -1, -1, -1, -1, -1, -1,
741 		                   25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1,
742 		                   33, 34, 35, 36, 37, 38, 39, 40, -1, -1, -1, -1, -1, -1, -1, -1 };
743 
744 	routine(out);
745 
746 	for(int row = 0; row < 4; row++)
747 	{
748 		for(int col = 0; col < 16; col++)
749 		{
750 			int i = row * 16 + col;
751 
752 			EXPECT_EQ(out[i], exp[i]);
753 		}
754 	}
755 }
756 
TEST(ReactorUnitTests,Concatenate)757 TEST(ReactorUnitTests, Concatenate)
758 {
759 	FunctionT<int(void *)> function;
760 	{
761 		Pointer<Byte> out = function.Arg<0>();
762 
763 		*Pointer<Int4>(out + 16 * 0) = Int4(Int2(0x04030201, 0x08070605), Int2(0x0C0B0A09, 0x100F0E0D));
764 		*Pointer<Short8>(out + 16 * 1) = Short8(Short4(0x0201, 0x0403, 0x0605, 0x0807), Short4(0x0A09, 0x0C0B, 0x0E0D, 0x100F));
765 
766 		Return(0);
767 	}
768 
769 	auto routine = function(testName().c_str());
770 
771 	int8_t ref[16 * 5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
772 		                   1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
773 
774 	int8_t out[16 * 5] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
775 		                   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
776 
777 	routine(out);
778 
779 	for(int row = 0; row < 2; row++)
780 	{
781 		for(int col = 0; col < 16; col++)
782 		{
783 			int i = row * 16 + col;
784 
785 			EXPECT_EQ(out[i], ref[i]) << "Row " << row << " column " << col << " not equal to reference.";
786 		}
787 	}
788 }
789 
TEST(ReactorUnitTests,Cast)790 TEST(ReactorUnitTests, Cast)
791 {
792 	FunctionT<void(void *)> function;
793 	{
794 		Pointer<Byte> out = function.Arg<0>();
795 
796 		Int4 c = Int4(0x01020304, 0x05060708, 0x09101112, 0x13141516);
797 		*Pointer<Short4>(out + 16 * 0) = Short4(c);
798 		*Pointer<Byte4>(out + 16 * 1 + 0) = Byte4(c);
799 		*Pointer<Byte4>(out + 16 * 1 + 4) = Byte4(As<Byte8>(c));
800 		*Pointer<Byte4>(out + 16 * 1 + 8) = Byte4(As<Short4>(c));
801 	}
802 
803 	auto routine = function(testName().c_str());
804 
805 	int out[2][4];
806 
807 	memset(&out, 0, sizeof(out));
808 
809 	routine(&out);
810 
811 	EXPECT_EQ(out[0][0], 0x07080304);
812 	EXPECT_EQ(out[0][1], 0x15161112);
813 
814 	EXPECT_EQ(out[1][0], 0x16120804);
815 	EXPECT_EQ(out[1][1], 0x01020304);
816 	EXPECT_EQ(out[1][2], 0x06080204);
817 }
818 
swizzleCode4(int i)819 static uint16_t swizzleCode4(int i)
820 {
821 	auto x = (i >> 0) & 0x03;
822 	auto y = (i >> 2) & 0x03;
823 	auto z = (i >> 4) & 0x03;
824 	auto w = (i >> 6) & 0x03;
825 	return static_cast<uint16_t>((x << 12) | (y << 8) | (z << 4) | (w << 0));
826 }
827 
TEST(ReactorUnitTests,Swizzle4)828 TEST(ReactorUnitTests, Swizzle4)
829 {
830 	FunctionT<void(void *)> function;
831 	{
832 		Pointer<Byte> out = function.Arg<0>();
833 
834 		for(int i = 0; i < 256; i++)
835 		{
836 			*Pointer<Float4>(out + 16 * i) = Swizzle(Float4(1.0f, 2.0f, 3.0f, 4.0f), swizzleCode4(i));
837 		}
838 
839 		for(int i = 0; i < 256; i++)
840 		{
841 			*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));
842 		}
843 
844 		*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));
845 		*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));
846 		*Pointer<Int2>(out + 16 * (512 + 2)) = UnpackLow(Short4(1, 2, 3, 4), Short4(5, 6, 7, 8));
847 		*Pointer<Int2>(out + 16 * (512 + 3)) = UnpackHigh(Short4(1, 2, 3, 4), Short4(5, 6, 7, 8));
848 		*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));
849 		*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));
850 
851 		for(int i = 0; i < 256; i++)
852 		{
853 			*Pointer<Short4>(out + 16 * (512 + 6) + (8 * i)) =
854 			    Swizzle(Short4(1, 2, 3, 4), swizzleCode4(i));
855 		}
856 
857 		for(int i = 0; i < 256; i++)
858 		{
859 			*Pointer<Int4>(out + 16 * (512 + 6 + i) + (8 * 256)) =
860 			    Swizzle(Int4(1, 2, 3, 4), swizzleCode4(i));
861 		}
862 	}
863 
864 	auto routine = function(testName().c_str());
865 
866 	struct
867 	{
868 		float f[256 + 256 + 2][4];
869 		int i[388][4];
870 	} out;
871 
872 	memset(&out, 0, sizeof(out));
873 
874 	routine(&out);
875 
876 	for(int i = 0; i < 256; i++)
877 	{
878 		EXPECT_EQ(out.f[i][0], float((i >> 0) & 0x03) + 1.0f);
879 		EXPECT_EQ(out.f[i][1], float((i >> 2) & 0x03) + 1.0f);
880 		EXPECT_EQ(out.f[i][2], float((i >> 4) & 0x03) + 1.0f);
881 		EXPECT_EQ(out.f[i][3], float((i >> 6) & 0x03) + 1.0f);
882 	}
883 
884 	for(int i = 0; i < 256; i++)
885 	{
886 		EXPECT_EQ(out.f[256 + i][0], float((i >> 0) & 0x03) + 1.0f);
887 		EXPECT_EQ(out.f[256 + i][1], float((i >> 2) & 0x03) + 1.0f);
888 		EXPECT_EQ(out.f[256 + i][2], float((i >> 4) & 0x03) + 5.0f);
889 		EXPECT_EQ(out.f[256 + i][3], float((i >> 6) & 0x03) + 5.0f);
890 	}
891 
892 	EXPECT_EQ(out.f[512 + 0][0], 1.0f);
893 	EXPECT_EQ(out.f[512 + 0][1], 5.0f);
894 	EXPECT_EQ(out.f[512 + 0][2], 2.0f);
895 	EXPECT_EQ(out.f[512 + 0][3], 6.0f);
896 
897 	EXPECT_EQ(out.f[512 + 1][0], 3.0f);
898 	EXPECT_EQ(out.f[512 + 1][1], 7.0f);
899 	EXPECT_EQ(out.f[512 + 1][2], 4.0f);
900 	EXPECT_EQ(out.f[512 + 1][3], 8.0f);
901 
902 	EXPECT_EQ(out.i[0][0], 0x00050001);
903 	EXPECT_EQ(out.i[0][1], 0x00060002);
904 	EXPECT_EQ(out.i[0][2], 0x00000000);
905 	EXPECT_EQ(out.i[0][3], 0x00000000);
906 
907 	EXPECT_EQ(out.i[1][0], 0x00070003);
908 	EXPECT_EQ(out.i[1][1], 0x00080004);
909 	EXPECT_EQ(out.i[1][2], 0x00000000);
910 	EXPECT_EQ(out.i[1][3], 0x00000000);
911 
912 	EXPECT_EQ(out.i[2][0], 0x0A020901);
913 	EXPECT_EQ(out.i[2][1], 0x0C040B03);
914 	EXPECT_EQ(out.i[2][2], 0x00000000);
915 	EXPECT_EQ(out.i[2][3], 0x00000000);
916 
917 	EXPECT_EQ(out.i[3][0], 0x0E060D05);
918 	EXPECT_EQ(out.i[3][1], 0x10080F07);
919 	EXPECT_EQ(out.i[3][2], 0x00000000);
920 	EXPECT_EQ(out.i[3][3], 0x00000000);
921 
922 	for(int i = 0; i < 256; i++)
923 	{
924 		EXPECT_EQ(out.i[4 + i / 2][0 + (i % 2) * 2] & 0xFFFF,
925 		          ((i >> 0) & 0x03) + 1);
926 		EXPECT_EQ(out.i[4 + i / 2][0 + (i % 2) * 2] >> 16,
927 		          ((i >> 2) & 0x03) + 1);
928 		EXPECT_EQ(out.i[4 + i / 2][1 + (i % 2) * 2] & 0xFFFF,
929 		          ((i >> 4) & 0x03) + 1);
930 		EXPECT_EQ(out.i[4 + i / 2][1 + (i % 2) * 2] >> 16,
931 		          ((i >> 6) & 0x03) + 1);
932 	}
933 
934 	for(int i = 0; i < 256; i++)
935 	{
936 		EXPECT_EQ(out.i[132 + i][0], ((i >> 0) & 0x03) + 1);
937 		EXPECT_EQ(out.i[132 + i][1], ((i >> 2) & 0x03) + 1);
938 		EXPECT_EQ(out.i[132 + i][2], ((i >> 4) & 0x03) + 1);
939 		EXPECT_EQ(out.i[132 + i][3], ((i >> 6) & 0x03) + 1);
940 	}
941 }
942 
TEST(ReactorUnitTests,Swizzle)943 TEST(ReactorUnitTests, Swizzle)
944 {
945 	FunctionT<void(void *)> function;
946 	{
947 		Pointer<Byte> out = function.Arg<0>();
948 
949 		Int4 c = Int4(0x01020304, 0x05060708, 0x09101112, 0x13141516);
950 		*Pointer<Byte16>(out + 16 * 0) = Swizzle(As<Byte16>(c), 0xFEDCBA9876543210ull);
951 		*Pointer<Byte8>(out + 16 * 1) = Swizzle(As<Byte8>(c), 0x76543210u);
952 		*Pointer<UShort8>(out + 16 * 2) = Swizzle(As<UShort8>(c), 0x76543210u);
953 	}
954 
955 	auto routine = function(testName().c_str());
956 
957 	int out[3][4];
958 
959 	memset(&out, 0, sizeof(out));
960 
961 	routine(&out);
962 
963 	EXPECT_EQ(out[0][0], 0x16151413);
964 	EXPECT_EQ(out[0][1], 0x12111009);
965 	EXPECT_EQ(out[0][2], 0x08070605);
966 	EXPECT_EQ(out[0][3], 0x04030201);
967 
968 	EXPECT_EQ(out[1][0], 0x08070605);
969 	EXPECT_EQ(out[1][1], 0x04030201);
970 
971 	EXPECT_EQ(out[2][0], 0x15161314);
972 	EXPECT_EQ(out[2][1], 0x11120910);
973 	EXPECT_EQ(out[2][2], 0x07080506);
974 	EXPECT_EQ(out[2][3], 0x03040102);
975 }
976 
TEST(ReactorUnitTests,Shuffle)977 TEST(ReactorUnitTests, Shuffle)
978 {
979 	// |select| is [0aaa:0bbb:0ccc:0ddd] where |aaa|, |bbb|, |ccc|
980 	// and |ddd| are 7-bit selection indices. For a total (1 << 12)
981 	// possibilities.
982 	const int kSelectRange = 1 << 12;
983 
984 	// Unfortunately, testing the whole kSelectRange results in a test
985 	// that is far too slow to run, because LLVM spends exponentially more
986 	// time optimizing the function below as the number of test cases
987 	// increases.
988 	//
989 	// To work-around the problem, only test a subset of the range by
990 	// skipping every kRangeIncrement value.
991 	//
992 	// Set this value to 1 if you want to test the whole implementation,
993 	// which will take a little less than 2 minutes on a fast workstation.
994 	//
995 	// The default value here takes about 1390ms, which is a little more than
996 	// what the Swizzle test takes (993 ms) on my machine. A non-power-of-2
997 	// value ensures a better spread over possible values.
998 	const int kRangeIncrement = 11;
999 
1000 	auto rangeIndexToSelect = [](int i) {
1001 		return static_cast<unsigned short>(
1002 		    (((i >> 9) & 7) << 0) |
1003 		    (((i >> 6) & 7) << 4) |
1004 		    (((i >> 3) & 7) << 8) |
1005 		    (((i >> 0) & 7) << 12));
1006 	};
1007 
1008 	FunctionT<int(void *)> function;
1009 	{
1010 		Pointer<Byte> out = function.Arg<0>();
1011 
1012 		for(int i = 0; i < kSelectRange; i += kRangeIncrement)
1013 		{
1014 			unsigned short select = rangeIndexToSelect(i);
1015 
1016 			*Pointer<Float4>(out + 16 * i) = Shuffle(Float4(1.0f, 2.0f, 3.0f, 4.0f),
1017 			                                         Float4(5.0f, 6.0f, 7.0f, 8.0f),
1018 			                                         select);
1019 
1020 			*Pointer<Int4>(out + (kSelectRange + i) * 16) = Shuffle(Int4(10, 11, 12, 13),
1021 			                                                        Int4(14, 15, 16, 17),
1022 			                                                        select);
1023 
1024 			*Pointer<UInt4>(out + (2 * kSelectRange + i) * 16) = Shuffle(UInt4(100, 101, 102, 103),
1025 			                                                             UInt4(104, 105, 106, 107),
1026 			                                                             select);
1027 		}
1028 
1029 		Return(0);
1030 	}
1031 
1032 	auto routine = function(testName().c_str());
1033 
1034 	struct
1035 	{
1036 		float f[kSelectRange][4];
1037 		int i[kSelectRange][4];
1038 		unsigned u[kSelectRange][4];
1039 	} out;
1040 
1041 	memset(&out, 0, sizeof(out));
1042 
1043 	routine(&out);
1044 
1045 	for(int i = 0; i < kSelectRange; i += kRangeIncrement)
1046 	{
1047 		EXPECT_EQ(out.f[i][0], float(1.0f + (i & 7)));
1048 		EXPECT_EQ(out.f[i][1], float(1.0f + ((i >> 3) & 7)));
1049 		EXPECT_EQ(out.f[i][2], float(1.0f + ((i >> 6) & 7)));
1050 		EXPECT_EQ(out.f[i][3], float(1.0f + ((i >> 9) & 7)));
1051 	}
1052 
1053 	for(int i = 0; i < kSelectRange; i += kRangeIncrement)
1054 	{
1055 		EXPECT_EQ(out.i[i][0], int(10 + (i & 7)));
1056 		EXPECT_EQ(out.i[i][1], int(10 + ((i >> 3) & 7)));
1057 		EXPECT_EQ(out.i[i][2], int(10 + ((i >> 6) & 7)));
1058 		EXPECT_EQ(out.i[i][3], int(10 + ((i >> 9) & 7)));
1059 	}
1060 
1061 	for(int i = 0; i < kSelectRange; i += kRangeIncrement)
1062 	{
1063 		EXPECT_EQ(out.u[i][0], unsigned(100 + (i & 7)));
1064 		EXPECT_EQ(out.u[i][1], unsigned(100 + ((i >> 3) & 7)));
1065 		EXPECT_EQ(out.u[i][2], unsigned(100 + ((i >> 6) & 7)));
1066 		EXPECT_EQ(out.u[i][3], unsigned(100 + ((i >> 9) & 7)));
1067 	}
1068 }
1069 
TEST(ReactorUnitTests,Branching)1070 TEST(ReactorUnitTests, Branching)
1071 {
1072 	FunctionT<int()> function;
1073 	{
1074 		Int x = 0;
1075 
1076 		For(Int i = 0, i < 8, i++)
1077 		{
1078 			If(i < 2)
1079 			{
1080 				x += 1;
1081 			}
1082 			Else If(i < 4)
1083 			{
1084 				x += 10;
1085 			}
1086 			Else If(i < 6)
1087 			{
1088 				x += 100;
1089 			}
1090 			Else
1091 			{
1092 				x += 1000;
1093 			}
1094 
1095 			For(Int i = 0, i < 5, i++)
1096 			    x += 10000;
1097 		}
1098 
1099 		For(Int i = 0, i < 10, i++) for(int i = 0; i < 10; i++)
1100 		    For(Int i = 0, i < 10, i++)
1101 		{
1102 			x += 1000000;
1103 		}
1104 
1105 		For(Int i = 0, i < 2, i++)
1106 		    If(x == 1000402222)
1107 		{
1108 			If(x != 1000402222)
1109 			    x += 1000000000;
1110 		}
1111 		Else
1112 		    x = -5;
1113 
1114 		Return(x);
1115 	}
1116 
1117 	auto routine = function(testName().c_str());
1118 
1119 	int result = routine();
1120 
1121 	EXPECT_EQ(result, 1000402222);
1122 }
1123 
TEST(ReactorUnitTests,MinMax)1124 TEST(ReactorUnitTests, MinMax)
1125 {
1126 	FunctionT<int(void *)> function;
1127 	{
1128 		Pointer<Byte> out = function.Arg<0>();
1129 
1130 		*Pointer<Float4>(out + 16 * 0) = Min(Float4(1.0f, 0.0f, -0.0f, +0.0f), Float4(0.0f, 1.0f, +0.0f, -0.0f));
1131 		*Pointer<Float4>(out + 16 * 1) = Max(Float4(1.0f, 0.0f, -0.0f, +0.0f), Float4(0.0f, 1.0f, +0.0f, -0.0f));
1132 
1133 		*Pointer<Int4>(out + 16 * 2) = Min(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
1134 		*Pointer<Int4>(out + 16 * 3) = Max(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
1135 		*Pointer<UInt4>(out + 16 * 4) = Min(UInt4(1, 0, -1, -0), UInt4(0, 1, 0, +0));
1136 		*Pointer<UInt4>(out + 16 * 5) = Max(UInt4(1, 0, -1, -0), UInt4(0, 1, 0, +0));
1137 
1138 		*Pointer<Short4>(out + 16 * 6) = Min(Short4(1, 0, -1, -0), Short4(0, 1, 0, +0));
1139 		*Pointer<Short4>(out + 16 * 7) = Max(Short4(1, 0, -1, -0), Short4(0, 1, 0, +0));
1140 		*Pointer<UShort4>(out + 16 * 8) = Min(UShort4(1, 0, -1, -0), UShort4(0, 1, 0, +0));
1141 		*Pointer<UShort4>(out + 16 * 9) = Max(UShort4(1, 0, -1, -0), UShort4(0, 1, 0, +0));
1142 
1143 		Return(0);
1144 	}
1145 
1146 	auto routine = function(testName().c_str());
1147 
1148 	unsigned int out[10][4];
1149 
1150 	memset(&out, 0, sizeof(out));
1151 
1152 	routine(&out);
1153 
1154 	EXPECT_EQ(out[0][0], 0x00000000u);
1155 	EXPECT_EQ(out[0][1], 0x00000000u);
1156 	EXPECT_EQ(out[0][2], 0x00000000u);
1157 	EXPECT_EQ(out[0][3], 0x80000000u);
1158 
1159 	EXPECT_EQ(out[1][0], 0x3F800000u);
1160 	EXPECT_EQ(out[1][1], 0x3F800000u);
1161 	EXPECT_EQ(out[1][2], 0x00000000u);
1162 	EXPECT_EQ(out[1][3], 0x80000000u);
1163 
1164 	EXPECT_EQ(out[2][0], 0x00000000u);
1165 	EXPECT_EQ(out[2][1], 0x00000000u);
1166 	EXPECT_EQ(out[2][2], 0xFFFFFFFFu);
1167 	EXPECT_EQ(out[2][3], 0x00000000u);
1168 
1169 	EXPECT_EQ(out[3][0], 0x00000001u);
1170 	EXPECT_EQ(out[3][1], 0x00000001u);
1171 	EXPECT_EQ(out[3][2], 0x00000000u);
1172 	EXPECT_EQ(out[3][3], 0x00000000u);
1173 
1174 	EXPECT_EQ(out[4][0], 0x00000000u);
1175 	EXPECT_EQ(out[4][1], 0x00000000u);
1176 	EXPECT_EQ(out[4][2], 0x00000000u);
1177 	EXPECT_EQ(out[4][3], 0x00000000u);
1178 
1179 	EXPECT_EQ(out[5][0], 0x00000001u);
1180 	EXPECT_EQ(out[5][1], 0x00000001u);
1181 	EXPECT_EQ(out[5][2], 0xFFFFFFFFu);
1182 	EXPECT_EQ(out[5][3], 0x00000000u);
1183 
1184 	EXPECT_EQ(out[6][0], 0x00000000u);
1185 	EXPECT_EQ(out[6][1], 0x0000FFFFu);
1186 	EXPECT_EQ(out[6][2], 0x00000000u);
1187 	EXPECT_EQ(out[6][3], 0x00000000u);
1188 
1189 	EXPECT_EQ(out[7][0], 0x00010001u);
1190 	EXPECT_EQ(out[7][1], 0x00000000u);
1191 	EXPECT_EQ(out[7][2], 0x00000000u);
1192 	EXPECT_EQ(out[7][3], 0x00000000u);
1193 
1194 	EXPECT_EQ(out[8][0], 0x00000000u);
1195 	EXPECT_EQ(out[8][1], 0x00000000u);
1196 	EXPECT_EQ(out[8][2], 0x00000000u);
1197 	EXPECT_EQ(out[8][3], 0x00000000u);
1198 
1199 	EXPECT_EQ(out[9][0], 0x00010001u);
1200 	EXPECT_EQ(out[9][1], 0x0000FFFFu);
1201 	EXPECT_EQ(out[9][2], 0x00000000u);
1202 	EXPECT_EQ(out[9][3], 0x00000000u);
1203 }
1204 
TEST(ReactorUnitTests,NotNeg)1205 TEST(ReactorUnitTests, NotNeg)
1206 {
1207 	FunctionT<int(void *)> function;
1208 	{
1209 		Pointer<Byte> out = function.Arg<0>();
1210 
1211 		*Pointer<Int>(out + 16 * 0) = ~Int(0x55555555);
1212 		*Pointer<Short>(out + 16 * 1) = ~Short(0x5555);
1213 		*Pointer<Int4>(out + 16 * 2) = ~Int4(0x55555555, 0xAAAAAAAA, 0x00000000, 0xFFFFFFFF);
1214 		*Pointer<Short4>(out + 16 * 3) = ~Short4(0x5555, 0xAAAA, 0x0000, 0xFFFF);
1215 
1216 		*Pointer<Int>(out + 16 * 4) = -Int(0x55555555);
1217 		*Pointer<Short>(out + 16 * 5) = -Short(0x5555);
1218 		*Pointer<Int4>(out + 16 * 6) = -Int4(0x55555555, 0xAAAAAAAA, 0x00000000, 0xFFFFFFFF);
1219 		*Pointer<Short4>(out + 16 * 7) = -Short4(0x5555, 0xAAAA, 0x0000, 0xFFFF);
1220 
1221 		*Pointer<Float4>(out + 16 * 8) = -Float4(1.0f, -1.0f, 0.0f, -0.0f);
1222 
1223 		Return(0);
1224 	}
1225 
1226 	auto routine = function(testName().c_str());
1227 
1228 	unsigned int out[10][4];
1229 
1230 	memset(&out, 0, sizeof(out));
1231 
1232 	routine(&out);
1233 
1234 	EXPECT_EQ(out[0][0], 0xAAAAAAAAu);
1235 	EXPECT_EQ(out[0][1], 0x00000000u);
1236 	EXPECT_EQ(out[0][2], 0x00000000u);
1237 	EXPECT_EQ(out[0][3], 0x00000000u);
1238 
1239 	EXPECT_EQ(out[1][0], 0x0000AAAAu);
1240 	EXPECT_EQ(out[1][1], 0x00000000u);
1241 	EXPECT_EQ(out[1][2], 0x00000000u);
1242 	EXPECT_EQ(out[1][3], 0x00000000u);
1243 
1244 	EXPECT_EQ(out[2][0], 0xAAAAAAAAu);
1245 	EXPECT_EQ(out[2][1], 0x55555555u);
1246 	EXPECT_EQ(out[2][2], 0xFFFFFFFFu);
1247 	EXPECT_EQ(out[2][3], 0x00000000u);
1248 
1249 	EXPECT_EQ(out[3][0], 0x5555AAAAu);
1250 	EXPECT_EQ(out[3][1], 0x0000FFFFu);
1251 	EXPECT_EQ(out[3][2], 0x00000000u);
1252 	EXPECT_EQ(out[3][3], 0x00000000u);
1253 
1254 	EXPECT_EQ(out[4][0], 0xAAAAAAABu);
1255 	EXPECT_EQ(out[4][1], 0x00000000u);
1256 	EXPECT_EQ(out[4][2], 0x00000000u);
1257 	EXPECT_EQ(out[4][3], 0x00000000u);
1258 
1259 	EXPECT_EQ(out[5][0], 0x0000AAABu);
1260 	EXPECT_EQ(out[5][1], 0x00000000u);
1261 	EXPECT_EQ(out[5][2], 0x00000000u);
1262 	EXPECT_EQ(out[5][3], 0x00000000u);
1263 
1264 	EXPECT_EQ(out[6][0], 0xAAAAAAABu);
1265 	EXPECT_EQ(out[6][1], 0x55555556u);
1266 	EXPECT_EQ(out[6][2], 0x00000000u);
1267 	EXPECT_EQ(out[6][3], 0x00000001u);
1268 
1269 	EXPECT_EQ(out[7][0], 0x5556AAABu);
1270 	EXPECT_EQ(out[7][1], 0x00010000u);
1271 	EXPECT_EQ(out[7][2], 0x00000000u);
1272 	EXPECT_EQ(out[7][3], 0x00000000u);
1273 
1274 	EXPECT_EQ(out[8][0], 0xBF800000u);
1275 	EXPECT_EQ(out[8][1], 0x3F800000u);
1276 	EXPECT_EQ(out[8][2], 0x80000000u);
1277 	EXPECT_EQ(out[8][3], 0x00000000u);
1278 }
1279 
TEST(ReactorUnitTests,RoundInt)1280 TEST(ReactorUnitTests, RoundInt)
1281 {
1282 	FunctionT<int(void *)> function;
1283 	{
1284 		Pointer<Byte> out = function.Arg<0>();
1285 
1286 		*Pointer<Int4>(out + 0) = RoundInt(Float4(3.1f, 3.6f, -3.1f, -3.6f));
1287 		*Pointer<Int4>(out + 16) = RoundIntClamped(Float4(2147483648.0f, -2147483648.0f, 2147483520, -2147483520));
1288 
1289 		Return(0);
1290 	}
1291 
1292 	auto routine = function(testName().c_str());
1293 
1294 	int out[2][4];
1295 
1296 	memset(&out, 0, sizeof(out));
1297 
1298 	routine(&out);
1299 
1300 	EXPECT_EQ(out[0][0], 3);
1301 	EXPECT_EQ(out[0][1], 4);
1302 	EXPECT_EQ(out[0][2], -3);
1303 	EXPECT_EQ(out[0][3], -4);
1304 
1305 	// x86 returns 0x80000000 for values which cannot be represented in a 32-bit
1306 	// integer, but RoundIntClamped() clamps to ensure a positive value for
1307 	// positive input. ARM saturates to the largest representable integers.
1308 	EXPECT_GE(out[1][0], 2147483520);
1309 	EXPECT_LT(out[1][1], -2147483647);
1310 	EXPECT_EQ(out[1][2], 2147483520);
1311 	EXPECT_EQ(out[1][3], -2147483520);
1312 }
1313 
TEST(ReactorUnitTests,FPtoUI)1314 TEST(ReactorUnitTests, FPtoUI)
1315 {
1316 	FunctionT<int(void *)> function;
1317 	{
1318 		Pointer<Byte> out = function.Arg<0>();
1319 
1320 		*Pointer<UInt>(out + 0) = UInt(Float(0xF0000000u));
1321 		*Pointer<UInt>(out + 4) = UInt(Float(0xC0000000u));
1322 		*Pointer<UInt>(out + 8) = UInt(Float(0x00000001u));
1323 		*Pointer<UInt>(out + 12) = UInt(Float(0xF000F000u));
1324 
1325 		*Pointer<UInt4>(out + 16) = UInt4(Float4(0xF0000000u, 0x80000000u, 0x00000000u, 0xCCCC0000u));
1326 
1327 		Return(0);
1328 	}
1329 
1330 	auto routine = function(testName().c_str());
1331 
1332 	unsigned int out[2][4];
1333 
1334 	memset(&out, 0, sizeof(out));
1335 
1336 	routine(&out);
1337 
1338 	EXPECT_EQ(out[0][0], 0xF0000000u);
1339 	EXPECT_EQ(out[0][1], 0xC0000000u);
1340 	EXPECT_EQ(out[0][2], 0x00000001u);
1341 	EXPECT_EQ(out[0][3], 0xF000F000u);
1342 
1343 	EXPECT_EQ(out[1][0], 0xF0000000u);
1344 	EXPECT_EQ(out[1][1], 0x80000000u);
1345 	EXPECT_EQ(out[1][2], 0x00000000u);
1346 	EXPECT_EQ(out[1][3], 0xCCCC0000u);
1347 }
1348 
TEST(ReactorUnitTests,VectorCompare)1349 TEST(ReactorUnitTests, VectorCompare)
1350 {
1351 	FunctionT<int(void *)> function;
1352 	{
1353 		Pointer<Byte> out = function.Arg<0>();
1354 
1355 		*Pointer<Int4>(out + 16 * 0) = CmpEQ(Float4(1.0f, 1.0f, -0.0f, +0.0f), Float4(0.0f, 1.0f, +0.0f, -0.0f));
1356 		*Pointer<Int4>(out + 16 * 1) = CmpEQ(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
1357 		*Pointer<Byte8>(out + 16 * 2) = CmpEQ(SByte8(1, 2, 3, 4, 5, 6, 7, 8), SByte8(7, 6, 5, 4, 3, 2, 1, 0));
1358 
1359 		*Pointer<Int4>(out + 16 * 3) = CmpNLT(Float4(1.0f, 1.0f, -0.0f, +0.0f), Float4(0.0f, 1.0f, +0.0f, -0.0f));
1360 		*Pointer<Int4>(out + 16 * 4) = CmpNLT(Int4(1, 0, -1, -0), Int4(0, 1, 0, +0));
1361 		*Pointer<Byte8>(out + 16 * 5) = CmpGT(SByte8(1, 2, 3, 4, 5, 6, 7, 8), SByte8(7, 6, 5, 4, 3, 2, 1, 0));
1362 
1363 		Return(0);
1364 	}
1365 
1366 	auto routine = function(testName().c_str());
1367 
1368 	unsigned int out[6][4];
1369 
1370 	memset(&out, 0, sizeof(out));
1371 
1372 	routine(&out);
1373 
1374 	EXPECT_EQ(out[0][0], 0x00000000u);
1375 	EXPECT_EQ(out[0][1], 0xFFFFFFFFu);
1376 	EXPECT_EQ(out[0][2], 0xFFFFFFFFu);
1377 	EXPECT_EQ(out[0][3], 0xFFFFFFFFu);
1378 
1379 	EXPECT_EQ(out[1][0], 0x00000000u);
1380 	EXPECT_EQ(out[1][1], 0x00000000u);
1381 	EXPECT_EQ(out[1][2], 0x00000000u);
1382 	EXPECT_EQ(out[1][3], 0xFFFFFFFFu);
1383 
1384 	EXPECT_EQ(out[2][0], 0xFF000000u);
1385 	EXPECT_EQ(out[2][1], 0x00000000u);
1386 
1387 	EXPECT_EQ(out[3][0], 0xFFFFFFFFu);
1388 	EXPECT_EQ(out[3][1], 0xFFFFFFFFu);
1389 	EXPECT_EQ(out[3][2], 0xFFFFFFFFu);
1390 	EXPECT_EQ(out[3][3], 0xFFFFFFFFu);
1391 
1392 	EXPECT_EQ(out[4][0], 0xFFFFFFFFu);
1393 	EXPECT_EQ(out[4][1], 0x00000000u);
1394 	EXPECT_EQ(out[4][2], 0x00000000u);
1395 	EXPECT_EQ(out[4][3], 0xFFFFFFFFu);
1396 
1397 	EXPECT_EQ(out[5][0], 0x00000000u);
1398 	EXPECT_EQ(out[5][1], 0xFFFFFFFFu);
1399 }
1400 
TEST(ReactorUnitTests,SaturatedAddAndSubtract)1401 TEST(ReactorUnitTests, SaturatedAddAndSubtract)
1402 {
1403 	FunctionT<int(void *)> function;
1404 	{
1405 		Pointer<Byte> out = function.Arg<0>();
1406 
1407 		*Pointer<Byte8>(out + 8 * 0) =
1408 		    AddSat(Byte8(1, 2, 3, 4, 5, 6, 7, 8),
1409 		           Byte8(7, 6, 5, 4, 3, 2, 1, 0));
1410 		*Pointer<Byte8>(out + 8 * 1) =
1411 		    AddSat(Byte8(0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE),
1412 		           Byte8(7, 6, 5, 4, 3, 2, 1, 0));
1413 		*Pointer<Byte8>(out + 8 * 2) =
1414 		    SubSat(Byte8(1, 2, 3, 4, 5, 6, 7, 8),
1415 		           Byte8(7, 6, 5, 4, 3, 2, 1, 0));
1416 
1417 		*Pointer<SByte8>(out + 8 * 3) =
1418 		    AddSat(SByte8(1, 2, 3, 4, 5, 6, 7, 8),
1419 		           SByte8(7, 6, 5, 4, 3, 2, 1, 0));
1420 		*Pointer<SByte8>(out + 8 * 4) =
1421 		    AddSat(SByte8(0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E),
1422 		           SByte8(7, 6, 5, 4, 3, 2, 1, 0));
1423 		*Pointer<SByte8>(out + 8 * 5) =
1424 		    AddSat(SByte8(0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88),
1425 		           SByte8(-7, -6, -5, -4, -3, -2, -1, -0));
1426 		*Pointer<SByte8>(out + 8 * 6) =
1427 		    SubSat(SByte8(0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88),
1428 		           SByte8(7, 6, 5, 4, 3, 2, 1, 0));
1429 
1430 		*Pointer<Short4>(out + 8 * 7) =
1431 		    AddSat(Short4(1, 2, 3, 4), Short4(3, 2, 1, 0));
1432 		*Pointer<Short4>(out + 8 * 8) =
1433 		    AddSat(Short4(0x7FFE, 0x7FFE, 0x7FFE, 0x7FFE),
1434 		           Short4(3, 2, 1, 0));
1435 		*Pointer<Short4>(out + 8 * 9) =
1436 		    AddSat(Short4(0x8001, 0x8002, 0x8003, 0x8004),
1437 		           Short4(-3, -2, -1, -0));
1438 		*Pointer<Short4>(out + 8 * 10) =
1439 		    SubSat(Short4(0x8001, 0x8002, 0x8003, 0x8004),
1440 		           Short4(3, 2, 1, 0));
1441 
1442 		*Pointer<UShort4>(out + 8 * 11) =
1443 		    AddSat(UShort4(1, 2, 3, 4), UShort4(3, 2, 1, 0));
1444 		*Pointer<UShort4>(out + 8 * 12) =
1445 		    AddSat(UShort4(0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE),
1446 		           UShort4(3, 2, 1, 0));
1447 		*Pointer<UShort4>(out + 8 * 13) =
1448 		    SubSat(UShort4(1, 2, 3, 4), UShort4(3, 2, 1, 0));
1449 
1450 		Return(0);
1451 	}
1452 
1453 	auto routine = function(testName().c_str());
1454 
1455 	unsigned int out[14][2];
1456 
1457 	memset(&out, 0, sizeof(out));
1458 
1459 	routine(&out);
1460 
1461 	EXPECT_EQ(out[0][0], 0x08080808u);
1462 	EXPECT_EQ(out[0][1], 0x08080808u);
1463 
1464 	EXPECT_EQ(out[1][0], 0xFFFFFFFFu);
1465 	EXPECT_EQ(out[1][1], 0xFEFFFFFFu);
1466 
1467 	EXPECT_EQ(out[2][0], 0x00000000u);
1468 	EXPECT_EQ(out[2][1], 0x08060402u);
1469 
1470 	EXPECT_EQ(out[3][0], 0x08080808u);
1471 	EXPECT_EQ(out[3][1], 0x08080808u);
1472 
1473 	EXPECT_EQ(out[4][0], 0x7F7F7F7Fu);
1474 	EXPECT_EQ(out[4][1], 0x7E7F7F7Fu);
1475 
1476 	EXPECT_EQ(out[5][0], 0x80808080u);
1477 	EXPECT_EQ(out[5][1], 0x88868482u);
1478 
1479 	EXPECT_EQ(out[6][0], 0x80808080u);
1480 	EXPECT_EQ(out[6][1], 0x88868482u);
1481 
1482 	EXPECT_EQ(out[7][0], 0x00040004u);
1483 	EXPECT_EQ(out[7][1], 0x00040004u);
1484 
1485 	EXPECT_EQ(out[8][0], 0x7FFF7FFFu);
1486 	EXPECT_EQ(out[8][1], 0x7FFE7FFFu);
1487 
1488 	EXPECT_EQ(out[9][0], 0x80008000u);
1489 	EXPECT_EQ(out[9][1], 0x80048002u);
1490 
1491 	EXPECT_EQ(out[10][0], 0x80008000u);
1492 	EXPECT_EQ(out[10][1], 0x80048002u);
1493 
1494 	EXPECT_EQ(out[11][0], 0x00040004u);
1495 	EXPECT_EQ(out[11][1], 0x00040004u);
1496 
1497 	EXPECT_EQ(out[12][0], 0xFFFFFFFFu);
1498 	EXPECT_EQ(out[12][1], 0xFFFEFFFFu);
1499 
1500 	EXPECT_EQ(out[13][0], 0x00000000u);
1501 	EXPECT_EQ(out[13][1], 0x00040002u);
1502 }
1503 
TEST(ReactorUnitTests,Unpack)1504 TEST(ReactorUnitTests, Unpack)
1505 {
1506 	FunctionT<int(void *, void *)> function;
1507 	{
1508 		Pointer<Byte> in = function.Arg<0>();
1509 		Pointer<Byte> out = function.Arg<1>();
1510 
1511 		Byte4 test_byte_a = *Pointer<Byte4>(in + 4 * 0);
1512 		Byte4 test_byte_b = *Pointer<Byte4>(in + 4 * 1);
1513 
1514 		*Pointer<Short4>(out + 8 * 0) =
1515 		    Unpack(test_byte_a, test_byte_b);
1516 
1517 		*Pointer<Short4>(out + 8 * 1) = Unpack(test_byte_a);
1518 
1519 		Return(0);
1520 	}
1521 
1522 	auto routine = function(testName().c_str());
1523 
1524 	unsigned int in[1][2];
1525 	unsigned int out[2][2];
1526 
1527 	memset(&out, 0, sizeof(out));
1528 
1529 	in[0][0] = 0xABCDEF12u;
1530 	in[0][1] = 0x34567890u;
1531 
1532 	routine(&in, &out);
1533 
1534 	EXPECT_EQ(out[0][0], 0x78EF9012u);
1535 	EXPECT_EQ(out[0][1], 0x34AB56CDu);
1536 
1537 	EXPECT_EQ(out[1][0], 0xEFEF1212u);
1538 	EXPECT_EQ(out[1][1], 0xABABCDCDu);
1539 }
1540 
TEST(ReactorUnitTests,Pack)1541 TEST(ReactorUnitTests, Pack)
1542 {
1543 	FunctionT<int(void *)> function;
1544 	{
1545 		Pointer<Byte> out = function.Arg<0>();
1546 
1547 		*Pointer<SByte8>(out + 8 * 0) =
1548 		    PackSigned(Short4(-1, -2, 1, 2),
1549 		               Short4(3, 4, -3, -4));
1550 
1551 		*Pointer<Byte8>(out + 8 * 1) =
1552 		    PackUnsigned(Short4(-1, -2, 1, 2),
1553 		                 Short4(3, 4, -3, -4));
1554 
1555 		*Pointer<Short8>(out + 8 * 2) =
1556 		    PackSigned(Int4(-1, -2, 1, 2),
1557 		               Int4(3, 4, -3, -4));
1558 
1559 		*Pointer<UShort8>(out + 8 * 4) =
1560 		    PackUnsigned(Int4(-1, -2, 1, 2),
1561 		                 Int4(3, 4, -3, -4));
1562 
1563 		Return(0);
1564 	}
1565 
1566 	auto routine = function(testName().c_str());
1567 
1568 	unsigned int out[6][2];
1569 
1570 	memset(&out, 0, sizeof(out));
1571 
1572 	routine(&out);
1573 
1574 	EXPECT_EQ(out[0][0], 0x0201FEFFu);
1575 	EXPECT_EQ(out[0][1], 0xFCFD0403u);
1576 
1577 	EXPECT_EQ(out[1][0], 0x02010000u);
1578 	EXPECT_EQ(out[1][1], 0x00000403u);
1579 
1580 	EXPECT_EQ(out[2][0], 0xFFFEFFFFu);
1581 	EXPECT_EQ(out[2][1], 0x00020001u);
1582 
1583 	EXPECT_EQ(out[3][0], 0x00040003u);
1584 	EXPECT_EQ(out[3][1], 0xFFFCFFFDu);
1585 
1586 	EXPECT_EQ(out[4][0], 0x00000000u);
1587 	EXPECT_EQ(out[4][1], 0x00020001u);
1588 
1589 	EXPECT_EQ(out[5][0], 0x00040003u);
1590 	EXPECT_EQ(out[5][1], 0x00000000u);
1591 }
1592 
TEST(ReactorUnitTests,MulHigh)1593 TEST(ReactorUnitTests, MulHigh)
1594 {
1595 	FunctionT<int(void *)> function;
1596 	{
1597 		Pointer<Byte> out = function.Arg<0>();
1598 
1599 		*Pointer<Short4>(out + 16 * 0) =
1600 		    MulHigh(Short4(0x01AA, 0x02DD, 0x03EE, 0xF422),
1601 		            Short4(0x01BB, 0x02CC, 0x03FF, 0xF411));
1602 		*Pointer<UShort4>(out + 16 * 1) =
1603 		    MulHigh(UShort4(0x01AA, 0x02DD, 0x03EE, 0xF422),
1604 		            UShort4(0x01BB, 0x02CC, 0x03FF, 0xF411));
1605 
1606 		*Pointer<Int4>(out + 16 * 2) =
1607 		    MulHigh(Int4(0x000001AA, 0x000002DD, 0xC8000000, 0xF8000000),
1608 		            Int4(0x000001BB, 0x84000000, 0x000003EE, 0xD7000000));
1609 		*Pointer<UInt4>(out + 16 * 3) =
1610 		    MulHigh(UInt4(0x000001AAu, 0x000002DDu, 0xC8000000u, 0xD8000000u),
1611 		            UInt4(0x000001BBu, 0x84000000u, 0x000003EEu, 0xD7000000u));
1612 
1613 		*Pointer<Int4>(out + 16 * 4) =
1614 		    MulHigh(Int4(0x7FFFFFFF, 0x7FFFFFFF, 0x80008000, 0xFFFFFFFF),
1615 		            Int4(0x7FFFFFFF, 0x80000000, 0x80008000, 0xFFFFFFFF));
1616 		*Pointer<UInt4>(out + 16 * 5) =
1617 		    MulHigh(UInt4(0x7FFFFFFFu, 0x7FFFFFFFu, 0x80008000u, 0xFFFFFFFFu),
1618 		            UInt4(0x7FFFFFFFu, 0x80000000u, 0x80008000u, 0xFFFFFFFFu));
1619 
1620 		// (U)Short8 variants currently unimplemented.
1621 
1622 		Return(0);
1623 	}
1624 
1625 	auto routine = function(testName().c_str());
1626 
1627 	unsigned int out[6][4];
1628 
1629 	memset(&out, 0, sizeof(out));
1630 
1631 	routine(&out);
1632 
1633 	EXPECT_EQ(out[0][0], 0x00080002u);
1634 	EXPECT_EQ(out[0][1], 0x008D000Fu);
1635 
1636 	EXPECT_EQ(out[1][0], 0x00080002u);
1637 	EXPECT_EQ(out[1][1], 0xE8C0000Fu);
1638 
1639 	EXPECT_EQ(out[2][0], 0x00000000u);
1640 	EXPECT_EQ(out[2][1], 0xFFFFFE9Cu);
1641 	EXPECT_EQ(out[2][2], 0xFFFFFF23u);
1642 	EXPECT_EQ(out[2][3], 0x01480000u);
1643 
1644 	EXPECT_EQ(out[3][0], 0x00000000u);
1645 	EXPECT_EQ(out[3][1], 0x00000179u);
1646 	EXPECT_EQ(out[3][2], 0x00000311u);
1647 	EXPECT_EQ(out[3][3], 0xB5680000u);
1648 
1649 	EXPECT_EQ(out[4][0], 0x3FFFFFFFu);
1650 	EXPECT_EQ(out[4][1], 0xC0000000u);
1651 	EXPECT_EQ(out[4][2], 0x3FFF8000u);
1652 	EXPECT_EQ(out[4][3], 0x00000000u);
1653 
1654 	EXPECT_EQ(out[5][0], 0x3FFFFFFFu);
1655 	EXPECT_EQ(out[5][1], 0x3FFFFFFFu);
1656 	EXPECT_EQ(out[5][2], 0x40008000u);
1657 	EXPECT_EQ(out[5][3], 0xFFFFFFFEu);
1658 }
1659 
TEST(ReactorUnitTests,MulAdd)1660 TEST(ReactorUnitTests, MulAdd)
1661 {
1662 	FunctionT<int(void *)> function;
1663 	{
1664 		Pointer<Byte> out = function.Arg<0>();
1665 
1666 		*Pointer<Int2>(out + 8 * 0) =
1667 		    MulAdd(Short4(0x1aa, 0x2dd, 0x3ee, 0xF422),
1668 		           Short4(0x1bb, 0x2cc, 0x3ff, 0xF411));
1669 
1670 		// (U)Short8 variant is mentioned but unimplemented
1671 		Return(0);
1672 	}
1673 
1674 	auto routine = function(testName().c_str());
1675 
1676 	unsigned int out[1][2];
1677 
1678 	memset(&out, 0, sizeof(out));
1679 
1680 	routine(&out);
1681 
1682 	EXPECT_EQ(out[0][0], 0x000AE34Au);
1683 	EXPECT_EQ(out[0][1], 0x009D5254u);
1684 }
1685 
TEST(ReactorUnitTests,PointersEqual)1686 TEST(ReactorUnitTests, PointersEqual)
1687 {
1688 	FunctionT<int(void *, void *)> function;
1689 	{
1690 		Pointer<Byte> ptrA = function.Arg<0>();
1691 		Pointer<Byte> ptrB = function.Arg<1>();
1692 		If(ptrA == ptrB)
1693 		{
1694 			Return(1);
1695 		}
1696 		Else
1697 		{
1698 			Return(0);
1699 		}
1700 	}
1701 
1702 	auto routine = function(testName().c_str());
1703 	int *a = reinterpret_cast<int *>(uintptr_t(0x0000000000000000));
1704 	int *b = reinterpret_cast<int *>(uintptr_t(0x00000000F0000000));
1705 	int *c = reinterpret_cast<int *>(uintptr_t(0xF000000000000000));
1706 	EXPECT_EQ(routine(&a, &a), 1);
1707 	EXPECT_EQ(routine(&b, &b), 1);
1708 	EXPECT_EQ(routine(&c, &c), 1);
1709 
1710 	EXPECT_EQ(routine(&a, &b), 0);
1711 	EXPECT_EQ(routine(&b, &a), 0);
1712 	EXPECT_EQ(routine(&b, &c), 0);
1713 	EXPECT_EQ(routine(&c, &b), 0);
1714 	EXPECT_EQ(routine(&c, &a), 0);
1715 	EXPECT_EQ(routine(&a, &c), 0);
1716 }
1717 
TEST(ReactorUnitTests,Args_2Mixed)1718 TEST(ReactorUnitTests, Args_2Mixed)
1719 {
1720 	// 2 mixed type args
1721 	FunctionT<float(int, float)> function;
1722 	{
1723 		Int a = function.Arg<0>();
1724 		Float b = function.Arg<1>();
1725 		Return(Float(a) + b);
1726 	}
1727 
1728 	if(auto routine = function(testName().c_str()))
1729 	{
1730 		float result = routine(1, 2.f);
1731 		EXPECT_EQ(result, 3.f);
1732 	}
1733 }
1734 
TEST(ReactorUnitTests,Args_4Mixed)1735 TEST(ReactorUnitTests, Args_4Mixed)
1736 {
1737 	// 4 mixed type args (max register allocation on Windows)
1738 	FunctionT<float(int, float, int, float)> function;
1739 	{
1740 		Int a = function.Arg<0>();
1741 		Float b = function.Arg<1>();
1742 		Int c = function.Arg<2>();
1743 		Float d = function.Arg<3>();
1744 		Return(Float(a) + b + Float(c) + d);
1745 	}
1746 
1747 	if(auto routine = function(testName().c_str()))
1748 	{
1749 		float result = routine(1, 2.f, 3, 4.f);
1750 		EXPECT_EQ(result, 10.f);
1751 	}
1752 }
1753 
TEST(ReactorUnitTests,Args_5Mixed)1754 TEST(ReactorUnitTests, Args_5Mixed)
1755 {
1756 	// 5 mixed type args (5th spills over to stack on Windows)
1757 	FunctionT<float(int, float, int, float, int)> function;
1758 	{
1759 		Int a = function.Arg<0>();
1760 		Float b = function.Arg<1>();
1761 		Int c = function.Arg<2>();
1762 		Float d = function.Arg<3>();
1763 		Int e = function.Arg<4>();
1764 		Return(Float(a) + b + Float(c) + d + Float(e));
1765 	}
1766 
1767 	if(auto routine = function(testName().c_str()))
1768 	{
1769 		float result = routine(1, 2.f, 3, 4.f, 5);
1770 		EXPECT_EQ(result, 15.f);
1771 	}
1772 }
1773 
TEST(ReactorUnitTests,Args_GreaterThan5Mixed)1774 TEST(ReactorUnitTests, Args_GreaterThan5Mixed)
1775 {
1776 	// >5 mixed type args
1777 	FunctionT<float(int, float, int, float, int, float, int, float, int, float)> function;
1778 	{
1779 		Int a = function.Arg<0>();
1780 		Float b = function.Arg<1>();
1781 		Int c = function.Arg<2>();
1782 		Float d = function.Arg<3>();
1783 		Int e = function.Arg<4>();
1784 		Float f = function.Arg<5>();
1785 		Int g = function.Arg<6>();
1786 		Float h = function.Arg<7>();
1787 		Int i = function.Arg<8>();
1788 		Float j = function.Arg<9>();
1789 		Return(Float(a) + b + Float(c) + d + Float(e) + f + Float(g) + h + Float(i) + j);
1790 	}
1791 
1792 	if(auto routine = function(testName().c_str()))
1793 	{
1794 		float result = routine(1, 2.f, 3, 4.f, 5, 6.f, 7, 8.f, 9, 10.f);
1795 		EXPECT_EQ(result, 55.f);
1796 	}
1797 }
1798 
1799 // This test was written because on Windows with Subzero, we would get a crash when executing a function
1800 // with a large number of local variables. The problem was that on Windows, 4K pages are allocated as
1801 // needed for the stack whenever an access is made in a "guard page", at which point the page is committed,
1802 // and the next 4K page becomes the guard page. If a stack access is made that's beyond the guard page,
1803 // a regular page fault occurs. To fix this, Subzero (and any compiler) now emits a call to __chkstk with
1804 // the stack size in EAX, so that it can probe the stack in 4K increments up to that size, committing the
1805 // required pages. See https://docs.microsoft.com/en-us/windows/win32/devnotes/-win32-chkstk.
TEST(ReactorUnitTests,LargeStack)1806 TEST(ReactorUnitTests, LargeStack)
1807 {
1808 	// An empirically large enough value to access outside the guard pages
1809 	constexpr int ArrayByteSize = 24 * 1024;
1810 	constexpr int ArraySize = ArrayByteSize / sizeof(int32_t);
1811 
1812 	FunctionT<void(int32_t * v)> function;
1813 	{
1814 		// Allocate a stack array large enough that writing to the first element will reach beyond
1815 		// the guard page.
1816 		Array<Int, ArraySize> largeStackArray;
1817 		for(int i = 0; i < ArraySize; ++i)
1818 		{
1819 			largeStackArray[i] = i;
1820 		}
1821 
1822 		Pointer<Int> in = function.Arg<0>();
1823 		for(int i = 0; i < ArraySize; ++i)
1824 		{
1825 			in[i] = largeStackArray[i];
1826 		}
1827 	}
1828 
1829 	// LLVM takes very long to generate this routine when InstructionCombining
1830 	// and O2 optimizations are enabled. Disable for now.
1831 	// TODO(b/174031014): Remove this once we fix LLVM taking so long
1832 	auto cfg = Config::Edit{}
1833 	               .remove(Optimization::Pass::InstructionCombining)
1834 	               .set(Optimization::Level::None);
1835 
1836 	auto routine = function(cfg, testName().c_str());
1837 
1838 	std::array<int32_t, ArraySize> v;
1839 
1840 	// Run this in a thread, so that we get the default reserved stack size (8K on Win64).
1841 	std::thread t([&] {
1842 		routine(v.data());
1843 	});
1844 	t.join();
1845 
1846 	for(int i = 0; i < ArraySize; ++i)
1847 	{
1848 		EXPECT_EQ(v[i], i);
1849 	}
1850 }
1851 
TEST(ReactorUnitTests,Call)1852 TEST(ReactorUnitTests, Call)
1853 {
1854 	struct Class
1855 	{
1856 		static int Callback(Class *p, int i, float f)
1857 		{
1858 			p->i = i;
1859 			p->f = f;
1860 			return i + int(f);
1861 		}
1862 
1863 		int i = 0;
1864 		float f = 0.0f;
1865 	};
1866 
1867 	FunctionT<int(void *)> function;
1868 	{
1869 		Pointer<Byte> c = function.Arg<0>();
1870 		auto res = Call(Class::Callback, c, 10, 20.0f);
1871 		Return(res);
1872 	}
1873 
1874 	auto routine = function(testName().c_str());
1875 
1876 	Class c;
1877 	int res = routine(&c);
1878 	EXPECT_EQ(res, 30);
1879 	EXPECT_EQ(c.i, 10);
1880 	EXPECT_EQ(c.f, 20.0f);
1881 }
1882 
TEST(ReactorUnitTests,CallMemberFunction)1883 TEST(ReactorUnitTests, CallMemberFunction)
1884 {
1885 	struct Class
1886 	{
1887 		int Callback(int argI, float argF)
1888 		{
1889 			i = argI;
1890 			f = argF;
1891 			return i + int(f);
1892 		}
1893 
1894 		int i = 0;
1895 		float f = 0.0f;
1896 	};
1897 
1898 	Class c;
1899 
1900 	FunctionT<int()> function;
1901 	{
1902 		auto res = Call(&Class::Callback, &c, 10, 20.0f);
1903 		Return(res);
1904 	}
1905 
1906 	auto routine = function(testName().c_str());
1907 
1908 	int res = routine();
1909 	EXPECT_EQ(res, 30);
1910 	EXPECT_EQ(c.i, 10);
1911 	EXPECT_EQ(c.f, 20.0f);
1912 }
1913 
TEST(ReactorUnitTests,CallMemberFunctionIndirect)1914 TEST(ReactorUnitTests, CallMemberFunctionIndirect)
1915 {
1916 	struct Class
1917 	{
1918 		int Callback(int argI, float argF)
1919 		{
1920 			i = argI;
1921 			f = argF;
1922 			return i + int(f);
1923 		}
1924 
1925 		int i = 0;
1926 		float f = 0.0f;
1927 	};
1928 
1929 	FunctionT<int(void *)> function;
1930 	{
1931 		Pointer<Byte> c = function.Arg<0>();
1932 		auto res = Call(&Class::Callback, c, 10, 20.0f);
1933 		Return(res);
1934 	}
1935 
1936 	auto routine = function(testName().c_str());
1937 
1938 	Class c;
1939 	int res = routine(&c);
1940 	EXPECT_EQ(res, 30);
1941 	EXPECT_EQ(c.i, 10);
1942 	EXPECT_EQ(c.f, 20.0f);
1943 }
1944 
TEST(ReactorUnitTests,CallImplicitCast)1945 TEST(ReactorUnitTests, CallImplicitCast)
1946 {
1947 	struct Class
1948 	{
1949 		static void Callback(Class *c, const char *s)
1950 		{
1951 			c->str = s;
1952 		}
1953 		std::string str;
1954 	};
1955 
1956 	FunctionT<void(Class * c, const char *s)> function;
1957 	{
1958 		Pointer<Byte> c = function.Arg<0>();
1959 		Pointer<Byte> s = function.Arg<1>();
1960 		Call(Class::Callback, c, s);
1961 	}
1962 
1963 	auto routine = function(testName().c_str());
1964 
1965 	Class c;
1966 	routine(&c, "hello world");
1967 	EXPECT_EQ(c.str, "hello world");
1968 }
1969 
TEST(ReactorUnitTests,CallBoolReturnFunction)1970 TEST(ReactorUnitTests, CallBoolReturnFunction)
1971 {
1972 	struct Class
1973 	{
1974 		static bool IsEven(int a)
1975 		{
1976 			return a % 2 == 0;
1977 		}
1978 	};
1979 
1980 	FunctionT<int(int)> function;
1981 	{
1982 		Int a = function.Arg<0>();
1983 		Bool res = Call(Class::IsEven, a);
1984 		If(res)
1985 		{
1986 			Return(1);
1987 		}
1988 		Return(0);
1989 	}
1990 
1991 	auto routine = function(testName().c_str());
1992 
1993 	for(int i = 0; i < 10; ++i)
1994 	{
1995 		EXPECT_EQ(routine(i), i % 2 == 0);
1996 	}
1997 }
1998 
TEST(ReactorUnitTests,Call_Args4)1999 TEST(ReactorUnitTests, Call_Args4)
2000 {
2001 	struct Class
2002 	{
2003 		static int Func(int a, int b, int c, int d)
2004 		{
2005 			return a + b + c + d;
2006 		}
2007 	};
2008 
2009 	{
2010 		FunctionT<int()> function;
2011 		{
2012 			auto res = Call(Class::Func, 1, 2, 3, 4);
2013 			Return(res);
2014 		}
2015 
2016 		auto routine = function(testName().c_str());
2017 
2018 		int res = routine();
2019 		EXPECT_EQ(res, 1 + 2 + 3 + 4);
2020 	}
2021 }
2022 
TEST(ReactorUnitTests,Call_Args5)2023 TEST(ReactorUnitTests, Call_Args5)
2024 {
2025 	struct Class
2026 	{
2027 		static int Func(int a, int b, int c, int d, int e)
2028 		{
2029 			return a + b + c + d + e;
2030 		}
2031 	};
2032 
2033 	{
2034 		FunctionT<int()> function;
2035 		{
2036 			auto res = Call(Class::Func, 1, 2, 3, 4, 5);
2037 			Return(res);
2038 		}
2039 
2040 		auto routine = function(testName().c_str());
2041 
2042 		int res = routine();
2043 		EXPECT_EQ(res, 1 + 2 + 3 + 4 + 5);
2044 	}
2045 }
2046 
TEST(ReactorUnitTests,Call_ArgsMany)2047 TEST(ReactorUnitTests, Call_ArgsMany)
2048 {
2049 	struct Class
2050 	{
2051 		static int Func(int a, int b, int c, int d, int e, int f, int g, int h)
2052 		{
2053 			return a + b + c + d + e + f + g + h;
2054 		}
2055 	};
2056 
2057 	{
2058 		FunctionT<int()> function;
2059 		{
2060 			auto res = Call(Class::Func, 1, 2, 3, 4, 5, 6, 7, 8);
2061 			Return(res);
2062 		}
2063 
2064 		auto routine = function(testName().c_str());
2065 
2066 		int res = routine();
2067 		EXPECT_EQ(res, 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8);
2068 	}
2069 }
2070 
TEST(ReactorUnitTests,Call_ArgsMixed)2071 TEST(ReactorUnitTests, Call_ArgsMixed)
2072 {
2073 	struct Class
2074 	{
2075 		static int Func(int a, float b, int *c, float *d, int e, float f, int *g, float *h)
2076 		{
2077 			return a + b + *c + *d + e + f + *g + *h;
2078 		}
2079 	};
2080 
2081 	{
2082 		FunctionT<int()> function;
2083 		{
2084 			Int c(3);
2085 			Float d(4);
2086 			Int g(7);
2087 			Float h(8);
2088 			auto res = Call(Class::Func, 1, 2.f, &c, &d, 5, 6.f, &g, &h);
2089 			Return(res);
2090 		}
2091 
2092 		auto routine = function(testName().c_str());
2093 
2094 		int res = routine();
2095 		EXPECT_EQ(res, 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8);
2096 	}
2097 }
2098 
TEST(ReactorUnitTests,Call_ArgsPointer)2099 TEST(ReactorUnitTests, Call_ArgsPointer)
2100 {
2101 	struct Class
2102 	{
2103 		static int Func(int *a)
2104 		{
2105 			return *a;
2106 		}
2107 	};
2108 
2109 	{
2110 		FunctionT<int()> function;
2111 		{
2112 			Int a(12345);
2113 			auto res = Call(Class::Func, &a);
2114 			Return(res);
2115 		}
2116 
2117 		auto routine = function(testName().c_str());
2118 
2119 		int res = routine();
2120 		EXPECT_EQ(res, 12345);
2121 	}
2122 }
2123 
TEST(ReactorUnitTests,CallExternalCallRoutine)2124 TEST(ReactorUnitTests, CallExternalCallRoutine)
2125 {
2126 	// routine1 calls Class::Func, passing it a pointer to routine2, and Class::Func calls routine2
2127 
2128 	auto routine2 = [] {
2129 		FunctionT<float(float, int)> function;
2130 		{
2131 			Float a = function.Arg<0>();
2132 			Int b = function.Arg<1>();
2133 			Return(a + Float(b));
2134 		}
2135 		return function("%s2", testName().c_str());
2136 	}();
2137 
2138 	struct Class
2139 	{
2140 		static float Func(void *p, float a, int b)
2141 		{
2142 			auto funcToCall = reinterpret_cast<float (*)(float, int)>(p);
2143 			return funcToCall(a, b);
2144 		}
2145 	};
2146 
2147 	auto routine1 = [] {
2148 		FunctionT<float(void *, float, int)> function;
2149 		{
2150 			Pointer<Byte> funcToCall = function.Arg<0>();
2151 			Float a = function.Arg<1>();
2152 			Int b = function.Arg<2>();
2153 			Float result = Call(Class::Func, funcToCall, a, b);
2154 			Return(result);
2155 		}
2156 		return function(testName().c_str());
2157 	}();
2158 
2159 	float result = routine1((void *)routine2.getEntry(), 12.f, 13);
2160 	EXPECT_EQ(result, 25.f);
2161 }
2162 
2163 // Check that a complex generated function which utilizes all 8 or 16 XMM
2164 // registers computes the correct result.
2165 // (Note that due to MSC's lack of support for inline assembly in x64,
2166 // this test does not actually check that the register contents are
2167 // preserved, just that the generated function computes the correct value.
2168 // It's necessary to inspect the registers in a debugger to actually verify.)
TEST(ReactorUnitTests,PreserveXMMRegisters)2169 TEST(ReactorUnitTests, PreserveXMMRegisters)
2170 {
2171 	FunctionT<void(void *, void *)> function;
2172 	{
2173 		Pointer<Byte> in = function.Arg<0>();
2174 		Pointer<Byte> out = function.Arg<1>();
2175 
2176 		Float4 a = *Pointer<Float4>(in + 16 * 0);
2177 		Float4 b = *Pointer<Float4>(in + 16 * 1);
2178 		Float4 c = *Pointer<Float4>(in + 16 * 2);
2179 		Float4 d = *Pointer<Float4>(in + 16 * 3);
2180 		Float4 e = *Pointer<Float4>(in + 16 * 4);
2181 		Float4 f = *Pointer<Float4>(in + 16 * 5);
2182 		Float4 g = *Pointer<Float4>(in + 16 * 6);
2183 		Float4 h = *Pointer<Float4>(in + 16 * 7);
2184 		Float4 i = *Pointer<Float4>(in + 16 * 8);
2185 		Float4 j = *Pointer<Float4>(in + 16 * 9);
2186 		Float4 k = *Pointer<Float4>(in + 16 * 10);
2187 		Float4 l = *Pointer<Float4>(in + 16 * 11);
2188 		Float4 m = *Pointer<Float4>(in + 16 * 12);
2189 		Float4 n = *Pointer<Float4>(in + 16 * 13);
2190 		Float4 o = *Pointer<Float4>(in + 16 * 14);
2191 		Float4 p = *Pointer<Float4>(in + 16 * 15);
2192 
2193 		Float4 ab = a + b;
2194 		Float4 cd = c + d;
2195 		Float4 ef = e + f;
2196 		Float4 gh = g + h;
2197 		Float4 ij = i + j;
2198 		Float4 kl = k + l;
2199 		Float4 mn = m + n;
2200 		Float4 op = o + p;
2201 
2202 		Float4 abcd = ab + cd;
2203 		Float4 efgh = ef + gh;
2204 		Float4 ijkl = ij + kl;
2205 		Float4 mnop = mn + op;
2206 
2207 		Float4 abcdefgh = abcd + efgh;
2208 		Float4 ijklmnop = ijkl + mnop;
2209 		Float4 sum = abcdefgh + ijklmnop;
2210 		*Pointer<Float4>(out) = sum;
2211 		Return();
2212 	}
2213 
2214 	auto routine = function(testName().c_str());
2215 	assert(routine);
2216 
2217 	float input[64] = { 1.0f, 0.0f, 0.0f, 0.0f,
2218 		                -1.0f, 1.0f, -1.0f, 0.0f,
2219 		                1.0f, 2.0f, -2.0f, 0.0f,
2220 		                -1.0f, 3.0f, -3.0f, 0.0f,
2221 		                1.0f, 4.0f, -4.0f, 0.0f,
2222 		                -1.0f, 5.0f, -5.0f, 0.0f,
2223 		                1.0f, 6.0f, -6.0f, 0.0f,
2224 		                -1.0f, 7.0f, -7.0f, 0.0f,
2225 		                1.0f, 8.0f, -8.0f, 0.0f,
2226 		                -1.0f, 9.0f, -9.0f, 0.0f,
2227 		                1.0f, 10.0f, -10.0f, 0.0f,
2228 		                -1.0f, 11.0f, -11.0f, 0.0f,
2229 		                1.0f, 12.0f, -12.0f, 0.0f,
2230 		                -1.0f, 13.0f, -13.0f, 0.0f,
2231 		                1.0f, 14.0f, -14.0f, 0.0f,
2232 		                -1.0f, 15.0f, -15.0f, 0.0f };
2233 
2234 	float result[4];
2235 
2236 	routine(input, result);
2237 
2238 	EXPECT_EQ(result[0], 0.0f);
2239 	EXPECT_EQ(result[1], 120.0f);
2240 	EXPECT_EQ(result[2], -120.0f);
2241 	EXPECT_EQ(result[3], 0.0f);
2242 }
2243 
2244 template<typename T>
2245 class CToReactorTCastTest : public ::testing::Test
2246 {
2247 public:
2248 	using CType = typename std::tuple_element<0, T>::type;
2249 	using ReactorType = typename std::tuple_element<1, T>::type;
2250 };
2251 
2252 using CToReactorTCastTestTypes = ::testing::Types<  // Subset of types that can be used as arguments.
2253                                                     //	std::pair<bool,         Bool>,    FIXME(capn): Not supported as argument type by Subzero.
2254                                                     //	std::pair<uint8_t,      Byte>,    FIXME(capn): Not supported as argument type by Subzero.
2255                                                     //	std::pair<int8_t,       SByte>,   FIXME(capn): Not supported as argument type by Subzero.
2256                                                     //	std::pair<int16_t,      Short>,   FIXME(capn): Not supported as argument type by Subzero.
2257                                                     //	std::pair<uint16_t,     UShort>,  FIXME(capn): Not supported as argument type by Subzero.
2258     std::pair<int, Int>,
2259     std::pair<unsigned int, UInt>,
2260     std::pair<float, Float>>;
2261 
2262 TYPED_TEST_SUITE(CToReactorTCastTest, CToReactorTCastTestTypes);
2263 
TYPED_TEST(CToReactorTCastTest,Casts)2264 TYPED_TEST(CToReactorTCastTest, Casts)
2265 {
2266 	using CType = typename TestFixture::CType;
2267 	using ReactorType = typename TestFixture::ReactorType;
2268 
2269 	std::shared_ptr<Routine> routine;
2270 
2271 	{
2272 		Function<Int(ReactorType)> function;
2273 		{
2274 			ReactorType a = function.template Arg<0>();
2275 			ReactorType b = CType{};
2276 			RValue<ReactorType> c = RValue<ReactorType>(CType{});
2277 			Bool same = (a == b) && (a == c);
2278 			Return(IfThenElse(same, Int(1), Int(0)));  // TODO: Ability to use Bools as return values.
2279 		}
2280 
2281 		routine = function(testName().c_str());
2282 
2283 		auto callable = (int (*)(CType))routine->getEntry();
2284 		CType in = {};
2285 		EXPECT_EQ(callable(in), 1);
2286 	}
2287 }
2288 
2289 template<typename T>
2290 class GEPTest : public ::testing::Test
2291 {
2292 public:
2293 	using CType = typename std::tuple_element<0, T>::type;
2294 	using ReactorType = typename std::tuple_element<1, T>::type;
2295 };
2296 
2297 using GEPTestTypes = ::testing::Types<
2298     std::pair<bool, Bool>,
2299     std::pair<int8_t, Byte>,
2300     std::pair<int8_t, SByte>,
2301     std::pair<int8_t[4], Byte4>,
2302     std::pair<int8_t[4], SByte4>,
2303     std::pair<int8_t[8], Byte8>,
2304     std::pair<int8_t[8], SByte8>,
2305     std::pair<int8_t[16], Byte16>,
2306     std::pair<int8_t[16], SByte16>,
2307     std::pair<int16_t, Short>,
2308     std::pair<int16_t, UShort>,
2309     std::pair<int16_t[2], Short2>,
2310     std::pair<int16_t[2], UShort2>,
2311     std::pair<int16_t[4], Short4>,
2312     std::pair<int16_t[4], UShort4>,
2313     std::pair<int16_t[8], Short8>,
2314     std::pair<int16_t[8], UShort8>,
2315     std::pair<int, Int>,
2316     std::pair<int, UInt>,
2317     std::pair<int[2], Int2>,
2318     std::pair<int[2], UInt2>,
2319     std::pair<int[4], Int4>,
2320     std::pair<int[4], UInt4>,
2321     std::pair<int64_t, Long>,
2322     std::pair<int16_t, Half>,
2323     std::pair<float, Float>,
2324     std::pair<float[2], Float2>,
2325     std::pair<float[4], Float4>>;
2326 
2327 TYPED_TEST_SUITE(GEPTest, GEPTestTypes);
2328 
TYPED_TEST(GEPTest,PtrOffsets)2329 TYPED_TEST(GEPTest, PtrOffsets)
2330 {
2331 	using CType = typename TestFixture::CType;
2332 	using ReactorType = typename TestFixture::ReactorType;
2333 
2334 	std::shared_ptr<Routine> routine;
2335 
2336 	{
2337 		Function<Pointer<ReactorType>(Pointer<ReactorType>, Int)> function;
2338 		{
2339 			Pointer<ReactorType> pointer = function.template Arg<0>();
2340 			Int index = function.template Arg<1>();
2341 			Return(&pointer[index]);
2342 		}
2343 
2344 		routine = function(testName().c_str());
2345 
2346 		auto callable = (CType * (*)(CType *, unsigned int)) routine->getEntry();
2347 
2348 		union PtrInt
2349 		{
2350 			CType *p;
2351 			size_t i;
2352 		};
2353 
2354 		PtrInt base;
2355 		base.i = 0x10000;
2356 
2357 		for(int i = 0; i < 5; i++)
2358 		{
2359 			PtrInt reference;
2360 			reference.p = &base.p[i];
2361 
2362 			PtrInt result;
2363 			result.p = callable(base.p, i);
2364 
2365 			auto expect = reference.i - base.i;
2366 			auto got = result.i - base.i;
2367 
2368 			EXPECT_EQ(got, expect) << "i:" << i;
2369 		}
2370 	}
2371 }
2372 
2373 static const std::vector<int> fibonacci = {
2374 	0,
2375 	1,
2376 	1,
2377 	2,
2378 	3,
2379 	5,
2380 	8,
2381 	13,
2382 	21,
2383 	34,
2384 	55,
2385 	89,
2386 	144,
2387 	233,
2388 	377,
2389 	610,
2390 	987,
2391 	1597,
2392 	2584,
2393 	4181,
2394 	6765,
2395 	10946,
2396 	17711,
2397 	28657,
2398 	46368,
2399 	75025,
2400 	121393,
2401 	196418,
2402 	317811,
2403 };
2404 
TEST(ReactorUnitTests,Fibonacci)2405 TEST(ReactorUnitTests, Fibonacci)
2406 {
2407 	FunctionT<int(int)> function;
2408 	{
2409 		Int n = function.Arg<0>();
2410 		Int current = 0;
2411 		Int next = 1;
2412 		For(Int i = 0, i < n, i++)
2413 		{
2414 			auto tmp = current + next;
2415 			current = next;
2416 			next = tmp;
2417 		}
2418 		Return(current);
2419 	}
2420 
2421 	auto routine = function(testName().c_str());
2422 
2423 	for(size_t i = 0; i < fibonacci.size(); i++)
2424 	{
2425 		EXPECT_EQ(routine(i), fibonacci[i]);
2426 	}
2427 }
2428 
TEST(ReactorUnitTests,Coroutines_Fibonacci)2429 TEST(ReactorUnitTests, Coroutines_Fibonacci)
2430 {
2431 	if(!rr::Caps.CoroutinesSupported)
2432 	{
2433 		SUCCEED() << "Coroutines not supported";
2434 		return;
2435 	}
2436 
2437 	Coroutine<int()> function;
2438 	{
2439 		Yield(Int(0));
2440 		Yield(Int(1));
2441 		Int current = 1;
2442 		Int next = 1;
2443 		While(true)
2444 		{
2445 			Yield(next);
2446 			auto tmp = current + next;
2447 			current = next;
2448 			next = tmp;
2449 		}
2450 	}
2451 	function.finalize(testName().c_str());
2452 
2453 	auto coroutine = function();
2454 
2455 	for(size_t i = 0; i < fibonacci.size(); i++)
2456 	{
2457 		int out = 0;
2458 		EXPECT_EQ(coroutine->await(out), true);
2459 		EXPECT_EQ(out, fibonacci[i]);
2460 	}
2461 }
2462 
TEST(ReactorUnitTests,Coroutines_Parameters)2463 TEST(ReactorUnitTests, Coroutines_Parameters)
2464 {
2465 	if(!rr::Caps.CoroutinesSupported)
2466 	{
2467 		SUCCEED() << "Coroutines not supported";
2468 		return;
2469 	}
2470 
2471 	Coroutine<uint8_t(uint8_t * data, int count)> function;
2472 	{
2473 		Pointer<Byte> data = function.Arg<0>();
2474 		Int count = function.Arg<1>();
2475 
2476 		For(Int i = 0, i < count, i++)
2477 		{
2478 			Yield(data[i]);
2479 		}
2480 	}
2481 	function.finalize(testName().c_str());
2482 
2483 	uint8_t data[] = { 10, 20, 30 };
2484 	auto coroutine = function(&data[0], 3);
2485 
2486 	uint8_t out = 0;
2487 	EXPECT_EQ(coroutine->await(out), true);
2488 	EXPECT_EQ(out, 10);
2489 	out = 0;
2490 	EXPECT_EQ(coroutine->await(out), true);
2491 	EXPECT_EQ(out, 20);
2492 	out = 0;
2493 	EXPECT_EQ(coroutine->await(out), true);
2494 	EXPECT_EQ(out, 30);
2495 	out = 99;
2496 	EXPECT_EQ(coroutine->await(out), false);
2497 	EXPECT_EQ(out, 99);
2498 	EXPECT_EQ(coroutine->await(out), false);
2499 	EXPECT_EQ(out, 99);
2500 }
2501 
2502 // This test was written because Subzero's handling of vector types
2503 // failed when more than one function is generated, as is the case
2504 // with coroutines.
TEST(ReactorUnitTests,Coroutines_Vectors)2505 TEST(ReactorUnitTests, Coroutines_Vectors)
2506 {
2507 	if(!rr::Caps.CoroutinesSupported)
2508 	{
2509 		SUCCEED() << "Coroutines not supported";
2510 		return;
2511 	}
2512 
2513 	Coroutine<int()> function;
2514 	{
2515 		Int4 a{ 1, 2, 3, 4 };
2516 		Yield(rr::Extract(a, 2));
2517 		Int4 b{ 5, 6, 7, 8 };
2518 		Yield(rr::Extract(b, 1));
2519 		Int4 c{ 9, 10, 11, 12 };
2520 		Yield(rr::Extract(c, 1));
2521 	}
2522 	function.finalize(testName().c_str());
2523 
2524 	auto coroutine = function();
2525 
2526 	int out;
2527 	coroutine->await(out);
2528 	EXPECT_EQ(out, 3);
2529 	coroutine->await(out);
2530 	EXPECT_EQ(out, 6);
2531 	coroutine->await(out);
2532 	EXPECT_EQ(out, 10);
2533 }
2534 
2535 // This test was written to make sure a coroutine without a Yield()
2536 // works correctly, by executing like a regular function with no
2537 // return (the return type is ignored).
2538 // We also run it twice to ensure per instance and/or global state
2539 // is properly cleaned up in between.
TEST(ReactorUnitTests,Coroutines_NoYield)2540 TEST(ReactorUnitTests, Coroutines_NoYield)
2541 {
2542 	if(!rr::Caps.CoroutinesSupported)
2543 	{
2544 		SUCCEED() << "Coroutines not supported";
2545 		return;
2546 	}
2547 
2548 	for(int i = 0; i < 2; ++i)
2549 	{
2550 		Coroutine<int()> function;
2551 		{
2552 			Int a;
2553 			a = 4;
2554 		}
2555 		function.finalize(testName().c_str());
2556 
2557 		auto coroutine = function();
2558 		int out;
2559 		EXPECT_EQ(coroutine->await(out), false);
2560 	}
2561 }
2562 
2563 // Test generating one coroutine, and executing it on multiple threads. This makes
2564 // sure the implementation manages per-call instance data correctly.
TEST(ReactorUnitTests,Coroutines_Parallel)2565 TEST(ReactorUnitTests, Coroutines_Parallel)
2566 {
2567 	if(!rr::Caps.CoroutinesSupported)
2568 	{
2569 		SUCCEED() << "Coroutines not supported";
2570 		return;
2571 	}
2572 
2573 	Coroutine<int()> function;
2574 	{
2575 		Yield(Int(0));
2576 		Yield(Int(1));
2577 		Int current = 1;
2578 		Int next = 1;
2579 		While(true)
2580 		{
2581 			Yield(next);
2582 			auto tmp = current + next;
2583 			current = next;
2584 			next = tmp;
2585 		}
2586 	}
2587 
2588 	// Must call on same thread that creates the coroutine
2589 	function.finalize(testName().c_str());
2590 
2591 	std::vector<std::thread> threads;
2592 	const size_t numThreads = 100;
2593 
2594 	for(size_t t = 0; t < numThreads; ++t)
2595 	{
2596 		threads.emplace_back([&] {
2597 			auto coroutine = function();
2598 
2599 			for(size_t i = 0; i < fibonacci.size(); i++)
2600 			{
2601 				int out = 0;
2602 				EXPECT_EQ(coroutine->await(out), true);
2603 				EXPECT_EQ(out, fibonacci[i]);
2604 			}
2605 		});
2606 	}
2607 
2608 	for(auto &t : threads)
2609 	{
2610 		t.join();
2611 	}
2612 }
2613 
2614 template<typename TestFuncType, typename RefFuncType, typename TestValueType>
2615 struct IntrinsicTestParams
2616 {
2617 	std::function<TestFuncType> testFunc;   // Function we're testing (Reactor)
2618 	std::function<RefFuncType> refFunc;     // Reference function to test against (C)
2619 	std::vector<TestValueType> testValues;  // Values to input to functions
2620 };
2621 
2622 using IntrinsicTestParams_Float = IntrinsicTestParams<RValue<Float>(RValue<Float>), float(float), float>;
2623 using IntrinsicTestParams_Float4 = IntrinsicTestParams<RValue<Float4>(RValue<Float4>), float(float), float>;
2624 using IntrinsicTestParams_Float4_Float4 = IntrinsicTestParams<RValue<Float4>(RValue<Float4>, RValue<Float4>), float(float, float), std::pair<float, float>>;
2625 
2626 // TODO(b/147818976): Each function has its own precision requirements for Vulkan, sometimes broken down
2627 // by input range. These are currently validated by deqp, but we can improve our own tests as well.
2628 // See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#spirvenv-precision-operation
2629 constexpr double INTRINSIC_PRECISION = 1e-4;
2630 
2631 struct IntrinsicTest_Float : public testing::TestWithParam<IntrinsicTestParams_Float>
2632 {
testIntrinsicTest_Float2633 	void test()
2634 	{
2635 		FunctionT<float(float)> function;
2636 		{
2637 			Return(GetParam().testFunc((Float(function.Arg<0>()))));
2638 		}
2639 
2640 		auto routine = function(testName().c_str());
2641 
2642 		for(auto &&v : GetParam().testValues)
2643 		{
2644 			SCOPED_TRACE(v);
2645 			EXPECT_NEAR(routine(v), GetParam().refFunc(v), INTRINSIC_PRECISION);
2646 		}
2647 	}
2648 };
2649 
2650 using float4 = float[4];
2651 using int4 = int[4];
2652 
2653 // TODO: Move to Reactor.hpp
2654 template<>
2655 struct rr::CToReactor<int[4]>
2656 {
2657 	using type = Int4;
2658 	static Int4 cast(float[4]);
2659 };
2660 
2661 // Value type wrapper around a <type>[4] (i.e. float4, int4)
2662 template<typename T>
2663 struct type4_value
2664 {
2665 	using E = typename std::remove_pointer_t<std::decay_t<T>>;
2666 
2667 	type4_value() = default;
type4_valuetype4_value2668 	explicit type4_value(E rep)
2669 	    : v{ rep, rep, rep, rep }
2670 	{}
type4_valuetype4_value2671 	type4_value(E x, E y, E z, E w)
2672 	    : v{ x, y, z, w }
2673 	{}
2674 
operator ==type4_value2675 	bool operator==(const type4_value &rhs) const
2676 	{
2677 		return std::equal(std::begin(v), std::end(v), rhs.v);
2678 	}
2679 
2680 	// For gtest printing
operator <<(std::ostream & os,const type4_value & value)2681 	friend std::ostream &operator<<(std::ostream &os, const type4_value &value)
2682 	{
2683 		return os << "[" << value.v[0] << ", " << value.v[1] << ", " << value.v[2] << ", " << value.v[3] << "]";
2684 	}
2685 
2686 	T v;
2687 };
2688 
2689 using float4_value = type4_value<float4>;
2690 using int4_value = type4_value<int4>;
2691 
2692 // Invoke a void(type4_value<T>*) routine on &v.v, returning wrapped result in v
2693 template<typename RoutineType, typename T>
invokeRoutine(RoutineType & routine,type4_value<T> v)2694 type4_value<T> invokeRoutine(RoutineType &routine, type4_value<T> v)
2695 {
2696 	routine(&v.v);
2697 	return v;
2698 }
2699 
2700 // Invoke a void(type4_value<T>*, type4_value<T>*) routine on &v1.v, &v2.v returning wrapped result in v1
2701 template<typename RoutineType, typename T>
invokeRoutine(RoutineType & routine,type4_value<T> v1,type4_value<T> v2)2702 type4_value<T> invokeRoutine(RoutineType &routine, type4_value<T> v1, type4_value<T> v2)
2703 {
2704 	routine(&v1.v, &v2.v);
2705 	return v1;
2706 }
2707 
2708 struct IntrinsicTest_Float4 : public testing::TestWithParam<IntrinsicTestParams_Float4>
2709 {
testIntrinsicTest_Float42710 	void test()
2711 	{
2712 		FunctionT<void(float4 *)> function;
2713 		{
2714 			Pointer<Float4> a = function.Arg<0>();
2715 			*a = GetParam().testFunc(*a);
2716 			Return();
2717 		}
2718 
2719 		auto routine = function(testName().c_str());
2720 
2721 		for(auto &&v : GetParam().testValues)
2722 		{
2723 			SCOPED_TRACE(v);
2724 			float4_value result = invokeRoutine(routine, float4_value{ v });
2725 			float4_value expected = float4_value{ GetParam().refFunc(v) };
2726 			EXPECT_NEAR(result.v[0], expected.v[0], INTRINSIC_PRECISION);
2727 			EXPECT_NEAR(result.v[1], expected.v[1], INTRINSIC_PRECISION);
2728 			EXPECT_NEAR(result.v[2], expected.v[2], INTRINSIC_PRECISION);
2729 			EXPECT_NEAR(result.v[3], expected.v[3], INTRINSIC_PRECISION);
2730 		}
2731 	}
2732 };
2733 
2734 struct IntrinsicTest_Float4_Float4 : public testing::TestWithParam<IntrinsicTestParams_Float4_Float4>
2735 {
testIntrinsicTest_Float4_Float42736 	void test()
2737 	{
2738 		FunctionT<void(float4 *, float4 *)> function;
2739 		{
2740 			Pointer<Float4> a = function.Arg<0>();
2741 			Pointer<Float4> b = function.Arg<1>();
2742 			*a = GetParam().testFunc(*a, *b);
2743 			Return();
2744 		}
2745 
2746 		auto routine = function(testName().c_str());
2747 
2748 		for(auto &&v : GetParam().testValues)
2749 		{
2750 			SCOPED_TRACE(v);
2751 			float4_value result = invokeRoutine(routine, float4_value{ v.first }, float4_value{ v.second });
2752 			float4_value expected = float4_value{ GetParam().refFunc(v.first, v.second) };
2753 			EXPECT_NEAR(result.v[0], expected.v[0], INTRINSIC_PRECISION);
2754 			EXPECT_NEAR(result.v[1], expected.v[1], INTRINSIC_PRECISION);
2755 			EXPECT_NEAR(result.v[2], expected.v[2], INTRINSIC_PRECISION);
2756 			EXPECT_NEAR(result.v[3], expected.v[3], INTRINSIC_PRECISION);
2757 		}
2758 	}
2759 };
2760 
2761 // clang-format off
2762 INSTANTIATE_TEST_SUITE_P(IntrinsicTestParams_Float, IntrinsicTest_Float, testing::Values(
__anon0eff22f30e02(Float v) 2763 	IntrinsicTestParams_Float{ [](Float v) { return rr::Exp2(v); }, exp2f, {0.f, 1.f, 123.f} },
__anon0eff22f30f02(Float v) 2764 	IntrinsicTestParams_Float{ [](Float v) { return rr::Log2(v); }, log2f, {1.f, 123.f} },
__anon0eff22f31202(Float v) 2765 	IntrinsicTestParams_Float{ [](Float v) { return rr::Sqrt(v); }, sqrtf, {0.f, 1.f, 123.f} }
2766 ));
2767 // clang-format on
2768 
2769 // TODO(b/149110874) Use coshf/sinhf when we've implemented SpirV versions at the SpirV level
vulkan_sinhf(float a)2770 float vulkan_sinhf(float a)
2771 {
2772 	return ((expf(a) - expf(-a)) / 2);
2773 }
vulkan_coshf(float a)2774 float vulkan_coshf(float a)
2775 {
2776 	return ((expf(a) + expf(-a)) / 2);
2777 }
2778 
2779 // clang-format off
2780 constexpr float PI = 3.141592653589793f;
2781 INSTANTIATE_TEST_SUITE_P(IntrinsicTestParams_Float4, IntrinsicTest_Float4, testing::Values(
__anon0eff22f31402(RValue<Float4> v) 2782 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Sin(v); },                    sinf,          {0.f, 1.f, PI, 123.f}  },
__anon0eff22f31602(RValue<Float4> v) 2783 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Cos(v); },                    cosf,          {0.f, 1.f, PI, 123.f}  },
__anon0eff22f31802(RValue<Float4> v) 2784 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Tan(v); },                    tanf,          {0.f, 1.f, PI, 123.f}  },
__anon0eff22f31a02(RValue<Float4> v) 2785 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Asin(v, Precision::Full); },  asinf,         {0.f, 1.f, -1.f}  },
__anon0eff22f31b02(RValue<Float4> v) 2786 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Acos(v, Precision::Full); },  acosf,         {0.f, 1.f, -1.f}  },
__anon0eff22f31d02(RValue<Float4> v) 2787 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Atan(v); },                   atanf,         {0.f, 1.f, PI, 123.f}  },
__anon0eff22f32002(RValue<Float4> v) 2788 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Sinh(v); },                   vulkan_sinhf,  {0.f, 1.f, PI}  },
__anon0eff22f32202(RValue<Float4> v) 2789 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Cosh(v); },                   vulkan_coshf,  {0.f, 1.f, PI} },
__anon0eff22f32402(RValue<Float4> v) 2790 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Tanh(v); },                   tanhf,         {0.f, 1.f, PI}  },
__anon0eff22f32602(RValue<Float4> v) 2791 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Asinh(v); },                  asinhf,        {0.f, 1.f, PI, 123.f}  },
__anon0eff22f32802(RValue<Float4> v) 2792 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Acosh(v); },                  acoshf,        {     1.f, PI, 123.f}  },
__anon0eff22f32902(RValue<Float4> v) 2793 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Atanh(v); },                  atanhf,        {0.f, 0.9999f, -0.9999f}  },
__anon0eff22f32b02(RValue<Float4> v) 2794 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Exp(v); },                    expf,          {0.f, 1.f, PI}  },
__anon0eff22f32d02(RValue<Float4> v) 2795 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Log(v); },                    logf,          {1.f, PI, 123.f}  },
__anon0eff22f33002(RValue<Float4> v) 2796 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Exp2(v); },                   exp2f,         {0.f, 1.f, PI, 123.f}  },
__anon0eff22f33102(RValue<Float4> v) 2797 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Log2(v); },                   log2f,         {1.f, PI, 123.f}  },
__anon0eff22f33302(RValue<Float4> v) 2798 	IntrinsicTestParams_Float4{ [](RValue<Float4> v) { return rr::Sqrt(v); },                   sqrtf,         {0.f, 1.f, PI, 123.f}  }
2799 ));
2800 // clang-format on
2801 
2802 // clang-format off
2803 INSTANTIATE_TEST_SUITE_P(IntrinsicTestParams_Float4_Float4, IntrinsicTest_Float4_Float4, testing::Values(
__anon0eff22f33502(RValue<Float4> v1, RValue<Float4> v2) 2804 	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} } },
__anon0eff22f33702(RValue<Float4> v1, RValue<Float4> v2) 2805 	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} } }
2806 ));
2807 // clang-format on
2808 
TEST_P(IntrinsicTest_Float,Test)2809 TEST_P(IntrinsicTest_Float, Test)
2810 {
2811 	test();
2812 }
TEST_P(IntrinsicTest_Float4,Test)2813 TEST_P(IntrinsicTest_Float4, Test)
2814 {
2815 	test();
2816 }
TEST_P(IntrinsicTest_Float4_Float4,Test)2817 TEST_P(IntrinsicTest_Float4_Float4, Test)
2818 {
2819 	test();
2820 }
2821 
TEST(ReactorUnitTests,Intrinsics_Ctlz)2822 TEST(ReactorUnitTests, Intrinsics_Ctlz)
2823 {
2824 	// ctlz: counts number of leading zeros
2825 
2826 	{
2827 		Function<UInt(UInt x)> function;
2828 		{
2829 			UInt x = function.Arg<0>();
2830 			Return(rr::Ctlz(x, false));
2831 		}
2832 		auto routine = function(testName().c_str());
2833 		auto callable = (uint32_t(*)(uint32_t))routine->getEntry();
2834 
2835 		for(uint32_t i = 0; i < 31; ++i)
2836 		{
2837 			uint32_t result = callable(1 << i);
2838 			EXPECT_EQ(result, 31 - i);
2839 		}
2840 
2841 		// Input 0 should return 32 for isZeroUndef == false
2842 		{
2843 			uint32_t result = callable(0);
2844 			EXPECT_EQ(result, 32u);
2845 		}
2846 	}
2847 
2848 	{
2849 		Function<Void(Pointer<UInt4>, UInt x)> function;
2850 		{
2851 			Pointer<UInt4> out = function.Arg<0>();
2852 			UInt x = function.Arg<1>();
2853 			*out = rr::Ctlz(UInt4(x), false);
2854 		}
2855 		auto routine = function(testName().c_str());
2856 		auto callable = (void (*)(uint32_t *, uint32_t))routine->getEntry();
2857 
2858 		uint32_t x[4];
2859 
2860 		for(uint32_t i = 0; i < 31; ++i)
2861 		{
2862 			callable(x, 1 << i);
2863 			EXPECT_EQ(x[0], 31 - i);
2864 			EXPECT_EQ(x[1], 31 - i);
2865 			EXPECT_EQ(x[2], 31 - i);
2866 			EXPECT_EQ(x[3], 31 - i);
2867 		}
2868 
2869 		// Input 0 should return 32 for isZeroUndef == false
2870 		{
2871 			callable(x, 0);
2872 			EXPECT_EQ(x[0], 32u);
2873 			EXPECT_EQ(x[1], 32u);
2874 			EXPECT_EQ(x[2], 32u);
2875 			EXPECT_EQ(x[3], 32u);
2876 		}
2877 	}
2878 }
2879 
TEST(ReactorUnitTests,Intrinsics_Cttz)2880 TEST(ReactorUnitTests, Intrinsics_Cttz)
2881 {
2882 	// cttz: counts number of trailing zeros
2883 
2884 	{
2885 		Function<UInt(UInt x)> function;
2886 		{
2887 			UInt x = function.Arg<0>();
2888 			Return(rr::Cttz(x, false));
2889 		}
2890 		auto routine = function(testName().c_str());
2891 		auto callable = (uint32_t(*)(uint32_t))routine->getEntry();
2892 
2893 		for(uint32_t i = 0; i < 31; ++i)
2894 		{
2895 			uint32_t result = callable(1 << i);
2896 			EXPECT_EQ(result, i);
2897 		}
2898 
2899 		// Input 0 should return 32 for isZeroUndef == false
2900 		{
2901 			uint32_t result = callable(0);
2902 			EXPECT_EQ(result, 32u);
2903 		}
2904 	}
2905 
2906 	{
2907 		Function<Void(Pointer<UInt4>, UInt x)> function;
2908 		{
2909 			Pointer<UInt4> out = function.Arg<0>();
2910 			UInt x = function.Arg<1>();
2911 			*out = rr::Cttz(UInt4(x), false);
2912 		}
2913 		auto routine = function(testName().c_str());
2914 		auto callable = (void (*)(uint32_t *, uint32_t))routine->getEntry();
2915 
2916 		uint32_t x[4];
2917 
2918 		for(uint32_t i = 0; i < 31; ++i)
2919 		{
2920 			callable(x, 1 << i);
2921 			EXPECT_EQ(x[0], i);
2922 			EXPECT_EQ(x[1], i);
2923 			EXPECT_EQ(x[2], i);
2924 			EXPECT_EQ(x[3], i);
2925 		}
2926 
2927 		// Input 0 should return 32 for isZeroUndef == false
2928 		{
2929 			callable(x, 0);
2930 			EXPECT_EQ(x[0], 32u);
2931 			EXPECT_EQ(x[1], 32u);
2932 			EXPECT_EQ(x[2], 32u);
2933 			EXPECT_EQ(x[3], 32u);
2934 		}
2935 	}
2936 }
2937 
TEST(ReactorUnitTests,Intrinsics_Scatter)2938 TEST(ReactorUnitTests, Intrinsics_Scatter)
2939 {
2940 	Function<Void(Pointer<Float> base, Pointer<Float4> val, Pointer<Int4> offsets)> function;
2941 	{
2942 		Pointer<Float> base = function.Arg<0>();
2943 		Pointer<Float4> val = function.Arg<1>();
2944 		Pointer<Int4> offsets = function.Arg<2>();
2945 
2946 		auto mask = Int4(~0, ~0, ~0, ~0);
2947 		unsigned int alignment = 1;
2948 		Scatter(base, *val, *offsets, mask, alignment);
2949 	}
2950 
2951 	float buffer[16] = { 0 };
2952 
2953 	constexpr auto elemSize = sizeof(buffer[0]);
2954 
2955 	int offsets[] = {
2956 		1 * elemSize,
2957 		6 * elemSize,
2958 		11 * elemSize,
2959 		13 * elemSize
2960 	};
2961 
2962 	float val[4] = { 10, 60, 110, 130 };
2963 
2964 	auto routine = function(testName().c_str());
2965 	auto entry = (void (*)(float *, float *, int *))routine->getEntry();
2966 
2967 	entry(buffer, val, offsets);
2968 
2969 	EXPECT_EQ(buffer[offsets[0] / sizeof(buffer[0])], 10);
2970 	EXPECT_EQ(buffer[offsets[1] / sizeof(buffer[0])], 60);
2971 	EXPECT_EQ(buffer[offsets[2] / sizeof(buffer[0])], 110);
2972 	EXPECT_EQ(buffer[offsets[3] / sizeof(buffer[0])], 130);
2973 }
2974 
TEST(ReactorUnitTests,Intrinsics_Gather)2975 TEST(ReactorUnitTests, Intrinsics_Gather)
2976 {
2977 	Function<Void(Pointer<Float> base, Pointer<Int4> offsets, Pointer<Float4> result)> function;
2978 	{
2979 		Pointer<Float> base = function.Arg<0>();
2980 		Pointer<Int4> offsets = function.Arg<1>();
2981 		Pointer<Float4> result = function.Arg<2>();
2982 
2983 		auto mask = Int4(~0, ~0, ~0, ~0);
2984 		unsigned int alignment = 1;
2985 		bool zeroMaskedLanes = true;
2986 		*result = Gather(base, *offsets, mask, alignment, zeroMaskedLanes);
2987 	}
2988 
2989 	float buffer[] = {
2990 		0, 10, 20, 30,
2991 		40, 50, 60, 70,
2992 		80, 90, 100, 110,
2993 		120, 130, 140, 150
2994 	};
2995 
2996 	constexpr auto elemSize = sizeof(buffer[0]);
2997 
2998 	int offsets[] = {
2999 		1 * elemSize,
3000 		6 * elemSize,
3001 		11 * elemSize,
3002 		13 * elemSize
3003 	};
3004 
3005 	auto routine = function(testName().c_str());
3006 	auto entry = (void (*)(float *, int *, float *))routine->getEntry();
3007 
3008 	float result[4] = {};
3009 	entry(buffer, offsets, result);
3010 
3011 	EXPECT_EQ(result[0], 10);
3012 	EXPECT_EQ(result[1], 60);
3013 	EXPECT_EQ(result[2], 110);
3014 	EXPECT_EQ(result[3], 130);
3015 }
3016 
TEST(ReactorUnitTests,ExtractFromRValue)3017 TEST(ReactorUnitTests, ExtractFromRValue)
3018 {
3019 	Function<Void(Pointer<Int4> values, Pointer<Int4> result)> function;
3020 	{
3021 		Pointer<Int4> vIn = function.Arg<0>();
3022 		Pointer<Int4> resultIn = function.Arg<1>();
3023 
3024 		RValue<Int4> v = *vIn;
3025 
3026 		Int4 result(678);
3027 
3028 		If(Extract(v, 0) == 42)
3029 		{
3030 			result = Insert(result, 1, 0);
3031 		}
3032 
3033 		If(Extract(v, 1) == 42)
3034 		{
3035 			result = Insert(result, 1, 1);
3036 		}
3037 
3038 		*resultIn = result;
3039 
3040 		Return();
3041 	}
3042 
3043 	auto routine = function(testName().c_str());
3044 	auto entry = (void (*)(int *, int *))routine->getEntry();
3045 
3046 	int v[4] = { 42, 42, 42, 42 };
3047 	int result[4] = { 99, 99, 99, 99 };
3048 	entry(v, result);
3049 	EXPECT_EQ(result[0], 1);
3050 	EXPECT_EQ(result[1], 1);
3051 	EXPECT_EQ(result[2], 678);
3052 	EXPECT_EQ(result[3], 678);
3053 }
3054 
TEST(ReactorUnitTests,AddAtomic)3055 TEST(ReactorUnitTests, AddAtomic)
3056 {
3057 	FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
3058 	{
3059 		Pointer<UInt> p = function.Arg<0>();
3060 		UInt a = function.Arg<1>();
3061 		UInt r = rr::AddAtomic(p, a, std::memory_order_relaxed);
3062 		Return(r);
3063 	}
3064 
3065 	auto routine = function(testName().c_str());
3066 	uint32_t x = 123;
3067 	uint32_t y = 456;
3068 	uint32_t prevX = routine(&x, y);
3069 	EXPECT_EQ(prevX, 123u);
3070 	EXPECT_EQ(x, 579u);
3071 }
3072 
TEST(ReactorUnitTests,SubAtomic)3073 TEST(ReactorUnitTests, SubAtomic)
3074 {
3075 	FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
3076 	{
3077 		Pointer<UInt> p = function.Arg<0>();
3078 		UInt a = function.Arg<1>();
3079 		UInt r = rr::SubAtomic(p, a, std::memory_order_relaxed);
3080 		Return(r);
3081 	}
3082 
3083 	auto routine = function(testName().c_str());
3084 	uint32_t x = 456;
3085 	uint32_t y = 123;
3086 	uint32_t prevX = routine(&x, y);
3087 	EXPECT_EQ(prevX, 456u);
3088 	EXPECT_EQ(x, 333u);
3089 }
3090 
TEST(ReactorUnitTests,AndAtomic)3091 TEST(ReactorUnitTests, AndAtomic)
3092 {
3093 	FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
3094 	{
3095 		Pointer<UInt> p = function.Arg<0>();
3096 		UInt a = function.Arg<1>();
3097 		UInt r = rr::AndAtomic(p, a, std::memory_order_relaxed);
3098 		Return(r);
3099 	}
3100 
3101 	auto routine = function(testName().c_str());
3102 	uint32_t x = 0b1111'0000;
3103 	uint32_t y = 0b1010'1100;
3104 	uint32_t prevX = routine(&x, y);
3105 	EXPECT_EQ(prevX, 0b1111'0000u);
3106 	EXPECT_EQ(x, 0b1010'0000u);
3107 }
3108 
TEST(ReactorUnitTests,OrAtomic)3109 TEST(ReactorUnitTests, OrAtomic)
3110 {
3111 	FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
3112 	{
3113 		Pointer<UInt> p = function.Arg<0>();
3114 		UInt a = function.Arg<1>();
3115 		UInt r = rr::OrAtomic(p, a, std::memory_order_relaxed);
3116 		Return(r);
3117 	}
3118 
3119 	auto routine = function(testName().c_str());
3120 	uint32_t x = 0b1111'0000;
3121 	uint32_t y = 0b1010'1100;
3122 	uint32_t prevX = routine(&x, y);
3123 	EXPECT_EQ(prevX, 0b1111'0000u);
3124 	EXPECT_EQ(x, 0b1111'1100u);
3125 }
3126 
TEST(ReactorUnitTests,XorAtomic)3127 TEST(ReactorUnitTests, XorAtomic)
3128 {
3129 	FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
3130 	{
3131 		Pointer<UInt> p = function.Arg<0>();
3132 		UInt a = function.Arg<1>();
3133 		UInt r = rr::XorAtomic(p, a, std::memory_order_relaxed);
3134 		Return(r);
3135 	}
3136 
3137 	auto routine = function(testName().c_str());
3138 	uint32_t x = 0b1111'0000;
3139 	uint32_t y = 0b1010'1100;
3140 	uint32_t prevX = routine(&x, y);
3141 	EXPECT_EQ(prevX, 0b1111'0000u);
3142 	EXPECT_EQ(x, 0b0101'1100u);
3143 }
3144 
TEST(ReactorUnitTests,MinAtomic)3145 TEST(ReactorUnitTests, MinAtomic)
3146 {
3147 	{
3148 		FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
3149 		{
3150 			Pointer<UInt> p = function.Arg<0>();
3151 			UInt a = function.Arg<1>();
3152 			UInt r = rr::MinAtomic(p, a, std::memory_order_relaxed);
3153 			Return(r);
3154 		}
3155 
3156 		auto routine = function(testName().c_str());
3157 		uint32_t x = 123;
3158 		uint32_t y = 100;
3159 		uint32_t prevX = routine(&x, y);
3160 		EXPECT_EQ(prevX, 123u);
3161 		EXPECT_EQ(x, 100u);
3162 	}
3163 
3164 	{
3165 		FunctionT<int32_t(int32_t * p, int32_t a)> function;
3166 		{
3167 			Pointer<Int> p = function.Arg<0>();
3168 			Int a = function.Arg<1>();
3169 			Int r = rr::MinAtomic(p, a, std::memory_order_relaxed);
3170 			Return(r);
3171 		}
3172 
3173 		auto routine = function(testName().c_str());
3174 		int32_t x = -123;
3175 		int32_t y = -200;
3176 		int32_t prevX = routine(&x, y);
3177 		EXPECT_EQ(prevX, -123);
3178 		EXPECT_EQ(x, -200);
3179 	}
3180 }
3181 
TEST(ReactorUnitTests,MaxAtomic)3182 TEST(ReactorUnitTests, MaxAtomic)
3183 {
3184 	{
3185 		FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
3186 		{
3187 			Pointer<UInt> p = function.Arg<0>();
3188 			UInt a = function.Arg<1>();
3189 			UInt r = rr::MaxAtomic(p, a, std::memory_order_relaxed);
3190 			Return(r);
3191 		}
3192 
3193 		auto routine = function(testName().c_str());
3194 		uint32_t x = 123;
3195 		uint32_t y = 100;
3196 		uint32_t prevX = routine(&x, y);
3197 		EXPECT_EQ(prevX, 123u);
3198 		EXPECT_EQ(x, 123u);
3199 	}
3200 
3201 	{
3202 		FunctionT<int32_t(int32_t * p, int32_t a)> function;
3203 		{
3204 			Pointer<Int> p = function.Arg<0>();
3205 			Int a = function.Arg<1>();
3206 			Int r = rr::MaxAtomic(p, a, std::memory_order_relaxed);
3207 			Return(r);
3208 		}
3209 
3210 		auto routine = function(testName().c_str());
3211 		int32_t x = -123;
3212 		int32_t y = -200;
3213 		int32_t prevX = routine(&x, y);
3214 		EXPECT_EQ(prevX, -123);
3215 		EXPECT_EQ(x, -123);
3216 	}
3217 }
3218 
TEST(ReactorUnitTests,ExchangeAtomic)3219 TEST(ReactorUnitTests, ExchangeAtomic)
3220 {
3221 	FunctionT<uint32_t(uint32_t * p, uint32_t a)> function;
3222 	{
3223 		Pointer<UInt> p = function.Arg<0>();
3224 		UInt a = function.Arg<1>();
3225 		UInt r = rr::ExchangeAtomic(p, a, std::memory_order_relaxed);
3226 		Return(r);
3227 	}
3228 
3229 	auto routine = function(testName().c_str());
3230 	uint32_t x = 123;
3231 	uint32_t y = 456;
3232 	uint32_t prevX = routine(&x, y);
3233 	EXPECT_EQ(prevX, 123u);
3234 	EXPECT_EQ(x, y);
3235 }
3236 
TEST(ReactorUnitTests,CompareExchangeAtomic)3237 TEST(ReactorUnitTests, CompareExchangeAtomic)
3238 {
3239 	FunctionT<uint32_t(uint32_t * x, uint32_t y, uint32_t compare)> function;
3240 	{
3241 		Pointer<UInt> x = function.Arg<0>();
3242 		UInt y = function.Arg<1>();
3243 		UInt compare = function.Arg<2>();
3244 		UInt r = rr::CompareExchangeAtomic(x, y, compare, std::memory_order_relaxed, std::memory_order_relaxed);
3245 		Return(r);
3246 	}
3247 
3248 	auto routine = function(testName().c_str());
3249 	uint32_t x = 123;
3250 	uint32_t y = 456;
3251 	uint32_t compare = 123;
3252 	uint32_t prevX = routine(&x, y, compare);
3253 	EXPECT_EQ(prevX, 123u);
3254 	EXPECT_EQ(x, y);
3255 
3256 	x = 123;
3257 	y = 456;
3258 	compare = 456;
3259 	prevX = routine(&x, y, compare);
3260 	EXPECT_EQ(prevX, 123u);
3261 	EXPECT_EQ(x, 123u);
3262 }
3263 
TEST(ReactorUnitTests,SRem)3264 TEST(ReactorUnitTests, SRem)
3265 {
3266 	FunctionT<void(int4 *, int4 *)> function;
3267 	{
3268 		Pointer<Int4> a = function.Arg<0>();
3269 		Pointer<Int4> b = function.Arg<1>();
3270 		*a = *a % *b;
3271 	}
3272 
3273 	auto routine = function(testName().c_str());
3274 
3275 	int4_value result = invokeRoutine(routine, int4_value{ 10, 11, 12, 13 }, int4_value{ 3, 3, 3, 3 });
3276 	int4_value expected = int4_value{ 10 % 3, 11 % 3, 12 % 3, 13 % 3 };
3277 	EXPECT_FLOAT_EQ(result.v[0], expected.v[0]);
3278 	EXPECT_FLOAT_EQ(result.v[1], expected.v[1]);
3279 	EXPECT_FLOAT_EQ(result.v[2], expected.v[2]);
3280 	EXPECT_FLOAT_EQ(result.v[3], expected.v[3]);
3281 }
3282 
TEST(ReactorUnitTests,FRem)3283 TEST(ReactorUnitTests, FRem)
3284 {
3285 	FunctionT<void(float4 *, float4 *)> function;
3286 	{
3287 		Pointer<Float4> a = function.Arg<0>();
3288 		Pointer<Float4> b = function.Arg<1>();
3289 		*a = *a % *b;
3290 	}
3291 
3292 	auto routine = function(testName().c_str());
3293 
3294 	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 });
3295 	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) };
3296 	EXPECT_FLOAT_EQ(result.v[0], expected.v[0]);
3297 	EXPECT_FLOAT_EQ(result.v[1], expected.v[1]);
3298 	EXPECT_FLOAT_EQ(result.v[2], expected.v[2]);
3299 	EXPECT_FLOAT_EQ(result.v[3], expected.v[3]);
3300 }
3301 
3302 // Subzero's load instruction assumes that a Constant ptr value is an offset, rather than an absolute
3303 // pointer, and would fail during codegen. This was fixed by casting the constant to a non-const
3304 // variable, and loading from it instead. This test makes sure this works.
TEST(ReactorUnitTests,LoadFromConstantData)3305 TEST(ReactorUnitTests, LoadFromConstantData)
3306 {
3307 	const int value = 123;
3308 
3309 	FunctionT<int()> function;
3310 	{
3311 		auto p = Pointer<Int>{ ConstantData(&value, sizeof(value)) };
3312 		Int v = *p;
3313 		Return(v);
3314 	}
3315 
3316 	const int result = function(testName().c_str())();
3317 	EXPECT_EQ(result, value);
3318 }
3319 
TEST(ReactorUnitTests,Multithreaded_Function)3320 TEST(ReactorUnitTests, Multithreaded_Function)
3321 {
3322 	constexpr int numThreads = 8;
3323 	constexpr int numLoops = 16;
3324 
3325 	auto threads = std::unique_ptr<std::thread[]>(new std::thread[numThreads]);
3326 	auto results = std::unique_ptr<int[]>(new int[numThreads * numLoops]);
3327 
3328 	for(int t = 0; t < numThreads; t++)
3329 	{
3330 		auto threadFunc = [&](int t) {
3331 			for(int l = 0; l < numLoops; l++)
3332 			{
3333 				FunctionT<int(int, int)> function;
3334 				{
3335 					Int a = function.Arg<0>();
3336 					Int b = function.Arg<1>();
3337 					Return((a << 16) | b);
3338 				}
3339 
3340 				auto f = function("%s_thread%d_loop%d", testName().c_str(), t, l);
3341 				results[t * numLoops + l] = f(t, l);
3342 			}
3343 		};
3344 		threads[t] = std::thread(threadFunc, t);
3345 	}
3346 
3347 	for(int t = 0; t < numThreads; t++)
3348 	{
3349 		threads[t].join();
3350 	}
3351 
3352 	for(int t = 0; t < numThreads; t++)
3353 	{
3354 		for(int l = 0; l < numLoops; l++)
3355 		{
3356 			auto expect = (t << 16) | l;
3357 			auto result = results[t * numLoops + l];
3358 			EXPECT_EQ(result, expect);
3359 		}
3360 	}
3361 }
3362 
TEST(ReactorUnitTests,Multithreaded_Coroutine)3363 TEST(ReactorUnitTests, Multithreaded_Coroutine)
3364 {
3365 	if(!rr::Caps.CoroutinesSupported)
3366 	{
3367 		SUCCEED() << "Coroutines not supported";
3368 		return;
3369 	}
3370 
3371 	constexpr int numThreads = 8;
3372 	constexpr int numLoops = 16;
3373 
3374 	struct Result
3375 	{
3376 		bool yieldReturns[3];
3377 		int yieldValues[3];
3378 	};
3379 
3380 	auto threads = std::unique_ptr<std::thread[]>(new std::thread[numThreads]);
3381 	auto results = std::unique_ptr<Result[]>(new Result[numThreads * numLoops]);
3382 
3383 	for(int t = 0; t < numThreads; t++)
3384 	{
3385 		auto threadFunc = [&](int t) {
3386 			for(int l = 0; l < numLoops; l++)
3387 			{
3388 				Coroutine<int(int, int)> function;
3389 				{
3390 					Int a = function.Arg<0>();
3391 					Int b = function.Arg<1>();
3392 					Yield(a);
3393 					Yield(b);
3394 				}
3395 				function.finalize((testName() + "_thread" + std::to_string(t) + "_loop" + std::to_string(l)).c_str());
3396 
3397 				auto coroutine = function(t, l);
3398 
3399 				auto &result = results[t * numLoops + l];
3400 				result = {};
3401 				result.yieldReturns[0] = coroutine->await(result.yieldValues[0]);
3402 				result.yieldReturns[1] = coroutine->await(result.yieldValues[1]);
3403 				result.yieldReturns[2] = coroutine->await(result.yieldValues[2]);
3404 			}
3405 		};
3406 		threads[t] = std::thread(threadFunc, t);
3407 	}
3408 
3409 	for(int t = 0; t < numThreads; t++)
3410 	{
3411 		threads[t].join();
3412 	}
3413 
3414 	for(int t = 0; t < numThreads; t++)
3415 	{
3416 		for(int l = 0; l < numLoops; l++)
3417 		{
3418 			auto const &result = results[t * numLoops + l];
3419 			EXPECT_EQ(result.yieldReturns[0], true);
3420 			EXPECT_EQ(result.yieldValues[0], t);
3421 			EXPECT_EQ(result.yieldReturns[1], true);
3422 			EXPECT_EQ(result.yieldValues[1], l);
3423 			EXPECT_EQ(result.yieldReturns[2], false);
3424 			EXPECT_EQ(result.yieldValues[2], 0);
3425 		}
3426 	}
3427 }
3428 
3429 // For gtest printing of pairs
3430 namespace std {
3431 template<typename T, typename U>
operator <<(std::ostream & os,const std::pair<T,U> & value)3432 std::ostream &operator<<(std::ostream &os, const std::pair<T, U> &value)
3433 {
3434 	return os << "{ " << value.first << ", " << value.second << " }";
3435 }
3436 }  // namespace std
3437 
3438 class StdOutCapture
3439 {
3440 public:
~StdOutCapture()3441 	~StdOutCapture()
3442 	{
3443 		stopIfCapturing();
3444 	}
3445 
start()3446 	void start()
3447 	{
3448 		stopIfCapturing();
3449 		capturing = true;
3450 		testing::internal::CaptureStdout();
3451 	}
3452 
stop()3453 	std::string stop()
3454 	{
3455 		assert(capturing);
3456 		capturing = false;
3457 		return testing::internal::GetCapturedStdout();
3458 	}
3459 
3460 private:
stopIfCapturing()3461 	void stopIfCapturing()
3462 	{
3463 		if(capturing)
3464 		{
3465 			// This stops the capture
3466 			testing::internal::GetCapturedStdout();
3467 		}
3468 	}
3469 
3470 	bool capturing = false;
3471 };
3472 
split(const std::string & s)3473 std::vector<std::string> split(const std::string &s)
3474 {
3475 	std::vector<std::string> result;
3476 	std::istringstream iss(s);
3477 	for(std::string line; std::getline(iss, line);)
3478 	{
3479 		result.push_back(line);
3480 	}
3481 	return result;
3482 }
3483 
TEST(ReactorUnitTests,PrintPrimitiveTypes)3484 TEST(ReactorUnitTests, PrintPrimitiveTypes)
3485 {
3486 #if defined(ENABLE_RR_PRINT) && !defined(ENABLE_RR_EMIT_PRINT_LOCATION)
3487 	FunctionT<void()> function;
3488 	{
3489 		bool b(true);
3490 		int8_t i8(-1);
3491 		uint8_t ui8(1);
3492 		int16_t i16(-1);
3493 		uint16_t ui16(1);
3494 		int32_t i32(-1);
3495 		uint32_t ui32(1);
3496 		int64_t i64(-1);
3497 		uint64_t ui64(1);
3498 		float f(1);
3499 		double d(2);
3500 		const char *cstr = "const char*";
3501 		std::string str = "std::string";
3502 		int *p = nullptr;
3503 
3504 		RR_WATCH(b);
3505 		RR_WATCH(i8);
3506 		RR_WATCH(ui8);
3507 		RR_WATCH(i16);
3508 		RR_WATCH(ui16);
3509 		RR_WATCH(i32);
3510 		RR_WATCH(ui32);
3511 		RR_WATCH(i64);
3512 		RR_WATCH(ui64);
3513 		RR_WATCH(f);
3514 		RR_WATCH(d);
3515 		RR_WATCH(cstr);
3516 		RR_WATCH(str);
3517 		RR_WATCH(p);
3518 	}
3519 
3520 	auto routine = function(testName().c_str());
3521 
3522 	char pNullptr[64];
3523 	snprintf(pNullptr, sizeof(pNullptr), "  p: %p", nullptr);
3524 
3525 	const char *expected[] = {
3526 		"  b: true",
3527 		"  i8: -1",
3528 		"  ui8: 1",
3529 		"  i16: -1",
3530 		"  ui16: 1",
3531 		"  i32: -1",
3532 		"  ui32: 1",
3533 		"  i64: -1",
3534 		"  ui64: 1",
3535 		"  f: 1.000000",
3536 		"  d: 2.000000",
3537 		"  cstr: const char*",
3538 		"  str: std::string",
3539 		pNullptr,
3540 	};
3541 	constexpr size_t expectedSize = sizeof(expected) / sizeof(expected[0]);
3542 
3543 	StdOutCapture capture;
3544 	capture.start();
3545 	routine();
3546 	auto output = split(capture.stop());
3547 	for(size_t i = 0, j = 1; i < expectedSize; ++i, j += 2)
3548 	{
3549 		ASSERT_EQ(expected[i], output[j]);
3550 	}
3551 
3552 #endif
3553 }
3554 
TEST(ReactorUnitTests,PrintReactorTypes)3555 TEST(ReactorUnitTests, PrintReactorTypes)
3556 {
3557 #if defined(ENABLE_RR_PRINT) && !defined(ENABLE_RR_EMIT_PRINT_LOCATION)
3558 	FunctionT<void()> function;
3559 	{
3560 		Bool b(true);
3561 		Int i(-1);
3562 		Int2 i2(-1, -2);
3563 		Int4 i4(-1, -2, -3, -4);
3564 		UInt ui(1);
3565 		UInt2 ui2(1, 2);
3566 		UInt4 ui4(1, 2, 3, 4);
3567 		Short s(-1);
3568 		Short4 s4(-1, -2, -3, -4);
3569 		UShort us(1);
3570 		UShort4 us4(1, 2, 3, 4);
3571 		Float f(1);
3572 		Float4 f4(1, 2, 3, 4);
3573 		Long l(i);
3574 		Pointer<Int> pi = nullptr;
3575 		RValue<Int> rvi = i;
3576 		Byte by('a');
3577 		Byte4 by4(i4);
3578 
3579 		RR_WATCH(b);
3580 		RR_WATCH(i);
3581 		RR_WATCH(i2);
3582 		RR_WATCH(i4);
3583 		RR_WATCH(ui);
3584 		RR_WATCH(ui2);
3585 		RR_WATCH(ui4);
3586 		RR_WATCH(s);
3587 		RR_WATCH(s4);
3588 		RR_WATCH(us);
3589 		RR_WATCH(us4);
3590 		RR_WATCH(f);
3591 		RR_WATCH(f4);
3592 		RR_WATCH(l);
3593 		RR_WATCH(pi);
3594 		RR_WATCH(rvi);
3595 		RR_WATCH(by);
3596 		RR_WATCH(by4);
3597 	}
3598 
3599 	auto routine = function(testName().c_str());
3600 
3601 	char piNullptr[64];
3602 	snprintf(piNullptr, sizeof(piNullptr), "  pi: %p", nullptr);
3603 
3604 	const char *expected[] = {
3605 		"  b: true",
3606 		"  i: -1",
3607 		"  i2: [-1, -2]",
3608 		"  i4: [-1, -2, -3, -4]",
3609 		"  ui: 1",
3610 		"  ui2: [1, 2]",
3611 		"  ui4: [1, 2, 3, 4]",
3612 		"  s: -1",
3613 		"  s4: [-1, -2, -3, -4]",
3614 		"  us: 1",
3615 		"  us4: [1, 2, 3, 4]",
3616 		"  f: 1.000000",
3617 		"  f4: [1.000000, 2.000000, 3.000000, 4.000000]",
3618 		"  l: -1",
3619 		piNullptr,
3620 		"  rvi: -1",
3621 		"  by: 97",
3622 		"  by4: [255, 254, 253, 252]",
3623 	};
3624 	constexpr size_t expectedSize = sizeof(expected) / sizeof(expected[0]);
3625 
3626 	StdOutCapture capture;
3627 	capture.start();
3628 	routine();
3629 	auto output = split(capture.stop());
3630 	for(size_t i = 0, j = 1; i < expectedSize; ++i, j += 2)
3631 	{
3632 		ASSERT_EQ(expected[i], output[j]);
3633 	}
3634 
3635 #endif
3636 }
3637 
3638 // Test constant <op> variable
3639 template<typename T, typename Func>
Arithmetic_LhsConstArg(T arg1,T arg2,Func f)3640 T Arithmetic_LhsConstArg(T arg1, T arg2, Func f)
3641 {
3642 	using ReactorT = CToReactorT<T>;
3643 
3644 	FunctionT<T(T)> function;
3645 	{
3646 		ReactorT lhs = arg1;
3647 		ReactorT rhs = function.template Arg<0>();
3648 		ReactorT result = f(lhs, rhs);
3649 		Return(result);
3650 	}
3651 
3652 	auto routine = function(testName().c_str());
3653 	return routine(arg2);
3654 }
3655 
3656 // Test variable <op> constant
3657 template<typename T, typename Func>
Arithmetic_RhsConstArg(T arg1,T arg2,Func f)3658 T Arithmetic_RhsConstArg(T arg1, T arg2, Func f)
3659 {
3660 	using ReactorT = CToReactorT<T>;
3661 
3662 	FunctionT<T(T)> function;
3663 	{
3664 		ReactorT lhs = function.template Arg<0>();
3665 		ReactorT rhs = arg2;
3666 		ReactorT result = f(lhs, rhs);
3667 		Return(result);
3668 	}
3669 
3670 	auto routine = function(testName().c_str());
3671 	return routine(arg1);
3672 }
3673 
3674 // Test constant <op> constant
3675 template<typename T, typename Func>
Arithmetic_TwoConstArgs(T arg1,T arg2,Func f)3676 T Arithmetic_TwoConstArgs(T arg1, T arg2, Func f)
3677 {
3678 	using ReactorT = CToReactorT<T>;
3679 
3680 	FunctionT<T()> function;
3681 	{
3682 		ReactorT lhs = arg1;
3683 		ReactorT rhs = arg2;
3684 		ReactorT result = f(lhs, rhs);
3685 		Return(result);
3686 	}
3687 
3688 	auto routine = function(testName().c_str());
3689 	return routine();
3690 }
3691 
3692 template<typename T, typename Func>
Arithmetic_ConstArgs(T arg1,T arg2,T expected,Func f)3693 void Arithmetic_ConstArgs(T arg1, T arg2, T expected, Func f)
3694 {
3695 	SCOPED_TRACE(std::to_string(arg1) + " <op> " + std::to_string(arg2) + " = " + std::to_string(expected));
3696 	T result{};
3697 	result = Arithmetic_LhsConstArg(arg1, arg2, std::forward<Func>(f));
3698 	EXPECT_EQ(result, expected);
3699 	result = Arithmetic_RhsConstArg(arg1, arg2, std::forward<Func>(f));
3700 	EXPECT_EQ(result, expected);
3701 	result = Arithmetic_TwoConstArgs(arg1, arg2, std::forward<Func>(f));
3702 	EXPECT_EQ(result, expected);
3703 }
3704 
3705 // Test that we generate valid code for when one or both args to arithmetic operations
3706 // are constant. In particular, we want to validate the case for two const args, as
3707 // often lowered instructions do not support this case.
TEST(ReactorUnitTests,Arithmetic_ConstantArgs)3708 TEST(ReactorUnitTests, Arithmetic_ConstantArgs)
3709 {
3710 	Arithmetic_ConstArgs(2, 3, 5, [](auto c1, auto c2) { return c1 + c2; });
3711 	Arithmetic_ConstArgs(5, 3, 2, [](auto c1, auto c2) { return c1 - c2; });
3712 	Arithmetic_ConstArgs(2, 3, 6, [](auto c1, auto c2) { return c1 * c2; });
3713 	Arithmetic_ConstArgs(6, 3, 2, [](auto c1, auto c2) { return c1 / c2; });
3714 	Arithmetic_ConstArgs(0xF0F0, 0xAAAA, 0xA0A0, [](auto c1, auto c2) { return c1 & c2; });
3715 	Arithmetic_ConstArgs(0xF0F0, 0xAAAA, 0xFAFA, [](auto c1, auto c2) { return c1 | c2; });
3716 	Arithmetic_ConstArgs(0xF0F0, 0xAAAA, 0x5A5A, [](auto c1, auto c2) { return c1 ^ c2; });
3717 
3718 	Arithmetic_ConstArgs(2.f, 3.f, 5.f, [](auto c1, auto c2) { return c1 + c2; });
3719 	Arithmetic_ConstArgs(5.f, 3.f, 2.f, [](auto c1, auto c2) { return c1 - c2; });
3720 	Arithmetic_ConstArgs(2.f, 3.f, 6.f, [](auto c1, auto c2) { return c1 * c2; });
3721 	Arithmetic_ConstArgs(6.f, 3.f, 2.f, [](auto c1, auto c2) { return c1 / c2; });
3722 }
3723 
3724 // Test for Subzero bad code-gen that was fixed in swiftshader-cl/50008
3725 // This tests the case of copying enough arguments to local variables so that the locals
3726 // get spilled to the stack when no more registers remain, and making sure these copies
3727 // are generated correctly. Without the aforementioned fix, this fails 100% on Windows x86.
TEST(ReactorUnitTests,SpillLocalCopiesOfArgs)3728 TEST(ReactorUnitTests, SpillLocalCopiesOfArgs)
3729 {
3730 	struct Helpers
3731 	{
3732 		static bool True() { return true; }
3733 	};
3734 
3735 	const int numLoops = 5;  // 2 should be enough, but loop more to make sure
3736 
3737 	FunctionT<int(int, int, int, int, int, int, int, int, int, int, int, int)> function;
3738 	{
3739 		Int result = 0;
3740 		Int a1 = function.Arg<0>();
3741 		Int a2 = function.Arg<1>();
3742 		Int a3 = function.Arg<2>();
3743 		Int a4 = function.Arg<3>();
3744 		Int a5 = function.Arg<4>();
3745 		Int a6 = function.Arg<5>();
3746 		Int a7 = function.Arg<6>();
3747 		Int a8 = function.Arg<7>();
3748 		Int a9 = function.Arg<8>();
3749 		Int a10 = function.Arg<9>();
3750 		Int a11 = function.Arg<10>();
3751 		Int a12 = function.Arg<11>();
3752 
3753 		for(int i = 0; i < numLoops; ++i)
3754 		{
3755 			// Copy all arguments to locals so that Ice::LocalVariableSplitter::handleSimpleVarAssign
3756 			// creates Variable copies of arguments. We loop so that we create enough of these so
3757 			// that some spill over to the stack.
3758 			Int i1 = a1;
3759 			Int i2 = a2;
3760 			Int i3 = a3;
3761 			Int i4 = a4;
3762 			Int i5 = a5;
3763 			Int i6 = a6;
3764 			Int i7 = a7;
3765 			Int i8 = a8;
3766 			Int i9 = a9;
3767 			Int i10 = a10;
3768 			Int i11 = a11;
3769 			Int i12 = a12;
3770 
3771 			// Forcibly materialize all variables so that Ice::Variable instances are created for each
3772 			// local; otherwise, Reactor r-value optimizations kick in, and the locals are elided.
3773 			Variable::materializeAll();
3774 
3775 			// We also need to create a separate block that uses the variables declared above
3776 			// so that rr::optimize() doesn't optimize them out when attempting to eliminate stores
3777 			// followed by a load in the same block.
3778 			If(Call(Helpers::True))
3779 			{
3780 				result += (i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 + i12);
3781 			}
3782 		}
3783 
3784 		Return(result);
3785 	}
3786 
3787 	auto routine = function(testName().c_str());
3788 	int result = routine(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
3789 	int expected = numLoops * (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12);
3790 	EXPECT_EQ(result, expected);
3791 }
3792 
3793 #if defined(ENABLE_RR_EMIT_ASM_FILE)
TEST(ReactorUnitTests,EmitAsm)3794 TEST(ReactorUnitTests, EmitAsm)
3795 {
3796 	// Only supported by LLVM for now
3797 	if(BackendName().find("LLVM") == std::string::npos) return;
3798 
3799 	namespace fs = std::filesystem;
3800 
3801 	FunctionT<int(void)> function;
3802 	{
3803 		Int sum;
3804 		For(Int i = 0, i < 10, i++)
3805 		{
3806 			sum += i;
3807 		}
3808 		Return(sum);
3809 	}
3810 
3811 	auto routine = function(testName().c_str());
3812 
3813 	// Returns path to first match of filename in current directory
3814 	auto findFile = [](const std::string filename) -> fs::path {
3815 		for(auto &p : fs::directory_iterator("."))
3816 		{
3817 			if(!p.is_regular_file())
3818 				continue;
3819 			auto currFilename = p.path().filename().string();
3820 			auto index = currFilename.find(testName());
3821 			if(index != std::string::npos)
3822 			{
3823 				return p.path();
3824 			}
3825 		}
3826 		return {};
3827 	};
3828 
3829 	fs::path path = findFile(testName());
3830 	EXPECT_FALSE(path.empty());
3831 
3832 	// Make sure an asm file was created
3833 	std::ifstream fin(path);
3834 	EXPECT_TRUE(fin);
3835 
3836 	// Make sure address of routine is in the file
3837 	auto findAddressInFile = [](std::ifstream &fin, size_t address) {
3838 		std::string addressString = [&] {
3839 			std::stringstream addressSS;
3840 			addressSS << "0x" << std::uppercase << std::hex << address;
3841 			return addressSS.str();
3842 		}();
3843 
3844 		std::string token;
3845 		while(fin >> token)
3846 		{
3847 			if(token.find(addressString) != std::string::npos)
3848 				return true;
3849 		}
3850 		return false;
3851 	};
3852 
3853 	size_t address = reinterpret_cast<size_t>(routine.getEntry());
3854 	EXPECT_TRUE(findAddressInFile(fin, address));
3855 
3856 	// Delete the file in case subsequent runs generate one with a different sequence number
3857 	fin.close();
3858 	std::filesystem::remove(path);
3859 }
3860 #endif
3861 
3862 ////////////////////////////////
3863 // Trait compile time checks. //
3864 ////////////////////////////////
3865 
3866 // Assert CToReactorT resolves to expected types.
3867 static_assert(std::is_same<CToReactorT<void>, Void>::value, "");
3868 static_assert(std::is_same<CToReactorT<bool>, Bool>::value, "");
3869 static_assert(std::is_same<CToReactorT<uint8_t>, Byte>::value, "");
3870 static_assert(std::is_same<CToReactorT<int8_t>, SByte>::value, "");
3871 static_assert(std::is_same<CToReactorT<int16_t>, Short>::value, "");
3872 static_assert(std::is_same<CToReactorT<uint16_t>, UShort>::value, "");
3873 static_assert(std::is_same<CToReactorT<int32_t>, Int>::value, "");
3874 static_assert(std::is_same<CToReactorT<uint64_t>, Long>::value, "");
3875 static_assert(std::is_same<CToReactorT<uint32_t>, UInt>::value, "");
3876 static_assert(std::is_same<CToReactorT<float>, Float>::value, "");
3877 
3878 // Assert CToReactorT for known pointer types resolves to expected types.
3879 static_assert(std::is_same<CToReactorT<void *>, Pointer<Byte>>::value, "");
3880 static_assert(std::is_same<CToReactorT<bool *>, Pointer<Bool>>::value, "");
3881 static_assert(std::is_same<CToReactorT<uint8_t *>, Pointer<Byte>>::value, "");
3882 static_assert(std::is_same<CToReactorT<int8_t *>, Pointer<SByte>>::value, "");
3883 static_assert(std::is_same<CToReactorT<int16_t *>, Pointer<Short>>::value, "");
3884 static_assert(std::is_same<CToReactorT<uint16_t *>, Pointer<UShort>>::value, "");
3885 static_assert(std::is_same<CToReactorT<int32_t *>, Pointer<Int>>::value, "");
3886 static_assert(std::is_same<CToReactorT<uint64_t *>, Pointer<Long>>::value, "");
3887 static_assert(std::is_same<CToReactorT<uint32_t *>, Pointer<UInt>>::value, "");
3888 static_assert(std::is_same<CToReactorT<float *>, Pointer<Float>>::value, "");
3889 static_assert(std::is_same<CToReactorT<uint16_t **>, Pointer<Pointer<UShort>>>::value, "");
3890 static_assert(std::is_same<CToReactorT<uint16_t ***>, Pointer<Pointer<Pointer<UShort>>>>::value, "");
3891 
3892 // Assert CToReactorT for unknown pointer types resolves to Pointer<Byte>.
3893 struct S
3894 {};
3895 static_assert(std::is_same<CToReactorT<S *>, Pointer<Byte>>::value, "");
3896 static_assert(std::is_same<CToReactorT<S **>, Pointer<Pointer<Byte>>>::value, "");
3897 static_assert(std::is_same<CToReactorT<S ***>, Pointer<Pointer<Pointer<Byte>>>>::value, "");
3898 
3899 // Assert IsRValue<> resolves true for RValue<> types.
3900 static_assert(IsRValue<RValue<Void>>::value, "");
3901 static_assert(IsRValue<RValue<Bool>>::value, "");
3902 static_assert(IsRValue<RValue<Byte>>::value, "");
3903 static_assert(IsRValue<RValue<SByte>>::value, "");
3904 static_assert(IsRValue<RValue<Short>>::value, "");
3905 static_assert(IsRValue<RValue<UShort>>::value, "");
3906 static_assert(IsRValue<RValue<Int>>::value, "");
3907 static_assert(IsRValue<RValue<Long>>::value, "");
3908 static_assert(IsRValue<RValue<UInt>>::value, "");
3909 static_assert(IsRValue<RValue<Float>>::value, "");
3910 
3911 // Assert IsLValue<> resolves true for LValue types.
3912 static_assert(IsLValue<Bool>::value, "");
3913 static_assert(IsLValue<Byte>::value, "");
3914 static_assert(IsLValue<SByte>::value, "");
3915 static_assert(IsLValue<Short>::value, "");
3916 static_assert(IsLValue<UShort>::value, "");
3917 static_assert(IsLValue<Int>::value, "");
3918 static_assert(IsLValue<Long>::value, "");
3919 static_assert(IsLValue<UInt>::value, "");
3920 static_assert(IsLValue<Float>::value, "");
3921 
3922 // Assert IsReference<> resolves true for Reference types.
3923 static_assert(IsReference<Reference<Bool>>::value, "");
3924 static_assert(IsReference<Reference<Byte>>::value, "");
3925 static_assert(IsReference<Reference<SByte>>::value, "");
3926 static_assert(IsReference<Reference<Short>>::value, "");
3927 static_assert(IsReference<Reference<UShort>>::value, "");
3928 static_assert(IsReference<Reference<Int>>::value, "");
3929 static_assert(IsReference<Reference<Long>>::value, "");
3930 static_assert(IsReference<Reference<UInt>>::value, "");
3931 static_assert(IsReference<Reference<Float>>::value, "");
3932 
3933 // Assert IsRValue<> resolves false for LValue types.
3934 static_assert(!IsRValue<Void>::value, "");
3935 static_assert(!IsRValue<Bool>::value, "");
3936 static_assert(!IsRValue<Byte>::value, "");
3937 static_assert(!IsRValue<SByte>::value, "");
3938 static_assert(!IsRValue<Short>::value, "");
3939 static_assert(!IsRValue<UShort>::value, "");
3940 static_assert(!IsRValue<Int>::value, "");
3941 static_assert(!IsRValue<Long>::value, "");
3942 static_assert(!IsRValue<UInt>::value, "");
3943 static_assert(!IsRValue<Float>::value, "");
3944 
3945 // Assert IsRValue<> resolves false for Reference types.
3946 static_assert(!IsRValue<Reference<Void>>::value, "");
3947 static_assert(!IsRValue<Reference<Bool>>::value, "");
3948 static_assert(!IsRValue<Reference<Byte>>::value, "");
3949 static_assert(!IsRValue<Reference<SByte>>::value, "");
3950 static_assert(!IsRValue<Reference<Short>>::value, "");
3951 static_assert(!IsRValue<Reference<UShort>>::value, "");
3952 static_assert(!IsRValue<Reference<Int>>::value, "");
3953 static_assert(!IsRValue<Reference<Long>>::value, "");
3954 static_assert(!IsRValue<Reference<UInt>>::value, "");
3955 static_assert(!IsRValue<Reference<Float>>::value, "");
3956 
3957 // Assert IsRValue<> resolves false for C types.
3958 static_assert(!IsRValue<void>::value, "");
3959 static_assert(!IsRValue<bool>::value, "");
3960 static_assert(!IsRValue<uint8_t>::value, "");
3961 static_assert(!IsRValue<int8_t>::value, "");
3962 static_assert(!IsRValue<int16_t>::value, "");
3963 static_assert(!IsRValue<uint16_t>::value, "");
3964 static_assert(!IsRValue<int32_t>::value, "");
3965 static_assert(!IsRValue<uint64_t>::value, "");
3966 static_assert(!IsRValue<uint32_t>::value, "");
3967 static_assert(!IsRValue<float>::value, "");
3968 
3969 // Assert IsLValue<> resolves false for RValue<> types.
3970 static_assert(!IsLValue<RValue<Void>>::value, "");
3971 static_assert(!IsLValue<RValue<Bool>>::value, "");
3972 static_assert(!IsLValue<RValue<Byte>>::value, "");
3973 static_assert(!IsLValue<RValue<SByte>>::value, "");
3974 static_assert(!IsLValue<RValue<Short>>::value, "");
3975 static_assert(!IsLValue<RValue<UShort>>::value, "");
3976 static_assert(!IsLValue<RValue<Int>>::value, "");
3977 static_assert(!IsLValue<RValue<Long>>::value, "");
3978 static_assert(!IsLValue<RValue<UInt>>::value, "");
3979 static_assert(!IsLValue<RValue<Float>>::value, "");
3980 
3981 // Assert IsLValue<> resolves false for Void type.
3982 static_assert(!IsLValue<Void>::value, "");
3983 
3984 // Assert IsLValue<> resolves false for Reference<> types.
3985 static_assert(!IsLValue<Reference<Void>>::value, "");
3986 static_assert(!IsLValue<Reference<Bool>>::value, "");
3987 static_assert(!IsLValue<Reference<Byte>>::value, "");
3988 static_assert(!IsLValue<Reference<SByte>>::value, "");
3989 static_assert(!IsLValue<Reference<Short>>::value, "");
3990 static_assert(!IsLValue<Reference<UShort>>::value, "");
3991 static_assert(!IsLValue<Reference<Int>>::value, "");
3992 static_assert(!IsLValue<Reference<Long>>::value, "");
3993 static_assert(!IsLValue<Reference<UInt>>::value, "");
3994 static_assert(!IsLValue<Reference<Float>>::value, "");
3995 
3996 // Assert IsLValue<> resolves false for C types.
3997 static_assert(!IsLValue<void>::value, "");
3998 static_assert(!IsLValue<bool>::value, "");
3999 static_assert(!IsLValue<uint8_t>::value, "");
4000 static_assert(!IsLValue<int8_t>::value, "");
4001 static_assert(!IsLValue<int16_t>::value, "");
4002 static_assert(!IsLValue<uint16_t>::value, "");
4003 static_assert(!IsLValue<int32_t>::value, "");
4004 static_assert(!IsLValue<uint64_t>::value, "");
4005 static_assert(!IsLValue<uint32_t>::value, "");
4006 static_assert(!IsLValue<float>::value, "");
4007 
4008 // Assert IsDefined<> resolves true for RValue<> types.
4009 static_assert(IsDefined<RValue<Void>>::value, "");
4010 static_assert(IsDefined<RValue<Bool>>::value, "");
4011 static_assert(IsDefined<RValue<Byte>>::value, "");
4012 static_assert(IsDefined<RValue<SByte>>::value, "");
4013 static_assert(IsDefined<RValue<Short>>::value, "");
4014 static_assert(IsDefined<RValue<UShort>>::value, "");
4015 static_assert(IsDefined<RValue<Int>>::value, "");
4016 static_assert(IsDefined<RValue<Long>>::value, "");
4017 static_assert(IsDefined<RValue<UInt>>::value, "");
4018 static_assert(IsDefined<RValue<Float>>::value, "");
4019 
4020 // Assert IsDefined<> resolves true for LValue types.
4021 static_assert(IsDefined<Void>::value, "");
4022 static_assert(IsDefined<Bool>::value, "");
4023 static_assert(IsDefined<Byte>::value, "");
4024 static_assert(IsDefined<SByte>::value, "");
4025 static_assert(IsDefined<Short>::value, "");
4026 static_assert(IsDefined<UShort>::value, "");
4027 static_assert(IsDefined<Int>::value, "");
4028 static_assert(IsDefined<Long>::value, "");
4029 static_assert(IsDefined<UInt>::value, "");
4030 static_assert(IsDefined<Float>::value, "");
4031 
4032 // Assert IsDefined<> resolves true for Reference<> types.
4033 static_assert(IsDefined<Reference<Bool>>::value, "");
4034 static_assert(IsDefined<Reference<Byte>>::value, "");
4035 static_assert(IsDefined<Reference<SByte>>::value, "");
4036 static_assert(IsDefined<Reference<Short>>::value, "");
4037 static_assert(IsDefined<Reference<UShort>>::value, "");
4038 static_assert(IsDefined<Reference<Int>>::value, "");
4039 static_assert(IsDefined<Reference<Long>>::value, "");
4040 static_assert(IsDefined<Reference<UInt>>::value, "");
4041 static_assert(IsDefined<Reference<Float>>::value, "");
4042 
4043 // Assert IsDefined<> resolves true for C types.
4044 static_assert(IsDefined<void>::value, "");
4045 static_assert(IsDefined<bool>::value, "");
4046 static_assert(IsDefined<uint8_t>::value, "");
4047 static_assert(IsDefined<int8_t>::value, "");
4048 static_assert(IsDefined<int16_t>::value, "");
4049 static_assert(IsDefined<uint16_t>::value, "");
4050 static_assert(IsDefined<int32_t>::value, "");
4051 static_assert(IsDefined<uint64_t>::value, "");
4052 static_assert(IsDefined<uint32_t>::value, "");
4053 static_assert(IsDefined<float>::value, "");
4054