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