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