• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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 "Reactor.hpp"
16 #include "SIMD.hpp"
17 
18 #include "gtest/gtest.h"
19 
20 using namespace rr;
21 
testName()22 static std::string testName()
23 {
24 	auto info = ::testing::UnitTest::GetInstance()->current_test_info();
25 	return std::string{ info->test_suite_name() } + "_" + info->name();
26 }
27 
TEST(ReactorSIMD,Add)28 TEST(ReactorSIMD, Add)
29 {
30 	ASSERT_GE(SIMD::Width, 4);
31 
32 	constexpr int arrayLength = 1024;
33 
34 	FunctionT<void(int *, int *, int *)> function;
35 	{
36 		Pointer<Int> r = Pointer<Int>(function.Arg<0>());
37 		Pointer<Int> a = Pointer<Int>(function.Arg<1>());
38 		Pointer<Int> b = Pointer<Int>(function.Arg<2>());
39 
40 		For(Int i = 0, i < arrayLength, i += SIMD::Width)
41 		{
42 			SIMD::Int x = *Pointer<SIMD::Int>(&a[i]);
43 			SIMD::Int y = *Pointer<SIMD::Int>(&b[i]);
44 
45 			SIMD::Int z = x + y;
46 
47 			*Pointer<SIMD::Int>(&r[i]) = z;
48 		}
49 	}
50 
51 	auto routine = function(testName().c_str());
52 
53 	int r[arrayLength] = {};
54 	int a[arrayLength];
55 	int b[arrayLength];
56 
57 	for(int i = 0; i < arrayLength; i++)
58 	{
59 		a[i] = i;
60 		b[i] = arrayLength + i;
61 	}
62 
63 	routine(r, a, b);
64 
65 	for(int i = 0; i < arrayLength; i++)
66 	{
67 		ASSERT_EQ(r[i], arrayLength + 2 * i);
68 	}
69 }
70 
TEST(ReactorSIMD,Broadcast)71 TEST(ReactorSIMD, Broadcast)
72 {
73 	FunctionT<void(int *, int)> function;
74 	{
75 		Pointer<Int> r = Pointer<Int>(function.Arg<0>());
76 		Int a = function.Arg<1>();
77 
78 		SIMD::Int x = a;
79 
80 		*Pointer<SIMD::Int>(r) = x;
81 	}
82 
83 	auto routine = function(testName().c_str());
84 
85 	std::vector<int> r(SIMD::Width);
86 
87 	for(int a = -2; a <= 2; a++)
88 	{
89 		routine(r.data(), a);
90 
91 		for(int i = 0; i < SIMD::Width; i++)
92 		{
93 			ASSERT_EQ(r[i], a);
94 		}
95 	}
96 }
97 
TEST(ReactorSIMD,InsertExtract128)98 TEST(ReactorSIMD, InsertExtract128)
99 {
100 	FunctionT<void(int *, int *)> function;
101 	{
102 		Pointer<Int> r = Pointer<Int>(function.Arg<0>());
103 		Pointer<Int> a = Pointer<Int>(function.Arg<1>());
104 
105 		SIMD::Int x = *Pointer<SIMD::Int>(a);
106 		SIMD::Int y = *Pointer<SIMD::Int>(r);
107 
108 		x -= y;
109 
110 		for(int i = 0; i < SIMD::Width / 4; i++)
111 		{
112 			y = Insert128(y, Extract128(x, i) << (i + 1), i);
113 		}
114 
115 		*Pointer<SIMD::Int>(r) = y;
116 	}
117 
118 	auto routine = function(testName().c_str());
119 
120 	std::vector<int> r(SIMD::Width);
121 	std::vector<int> a(SIMD::Width);
122 
123 	for(int i = 0; i < SIMD::Width; i++)
124 	{
125 		r[i] = 0;
126 		a[i] = 1 + i;
127 	}
128 
129 	routine(r.data(), a.data());
130 
131 	for(int i = 0; i < SIMD::Width; i++)
132 	{
133 		ASSERT_EQ(r[i], a[i] << (i / 4 + 1));
134 	}
135 }
136 
TEST(ReactorSIMD,Intrinsics_Scatter)137 TEST(ReactorSIMD, Intrinsics_Scatter)
138 {
139 	Function<Void(Pointer<Float> base, Pointer<SIMD::Float> val, Pointer<SIMD::Int> offsets)> function;
140 	{
141 		Pointer<Float> base = function.Arg<0>();
142 		Pointer<SIMD::Float> val = function.Arg<1>();
143 		Pointer<SIMD::Int> offsets = function.Arg<2>();
144 
145 		SIMD::Int mask = ~0;
146 		unsigned int alignment = 1;
147 		Scatter(base, *val, *offsets, mask, alignment);
148 	}
149 
150 	std::vector<float> buffer(10 + 10 * SIMD::Width);
151 	std::vector<int> offsets(SIMD::Width);
152 	std::vector<float> val(SIMD::Width);
153 
154 	for(int i = 0; i < SIMD::Width; i++)
155 	{
156 		offsets[i] = (3 + 7 * i) * sizeof(float);
157 		val[i] = 13.0f + 17.0f * i;
158 	}
159 
160 	auto routine = function(testName().c_str());
161 	auto entry = (void (*)(float *, float *, int *))routine->getEntry();
162 
163 	entry(buffer.data(), val.data(), offsets.data());
164 
165 	for(int i = 0; i < SIMD::Width; i++)
166 	{
167 		EXPECT_EQ(buffer[offsets[i] / sizeof(float)], val[i]);
168 	}
169 }
170 
TEST(ReactorSIMD,Intrinsics_Gather)171 TEST(ReactorSIMD, Intrinsics_Gather)
172 {
173 	Function<Void(Pointer<Float> base, Pointer<SIMD::Int> offsets, Pointer<SIMD::Float> result)> function;
174 	{
175 		Pointer<Float> base = function.Arg<0>();
176 		Pointer<SIMD::Int> offsets = function.Arg<1>();
177 		Pointer<SIMD::Float> result = function.Arg<2>();
178 
179 		SIMD::Int mask = ~0;
180 		unsigned int alignment = 1;
181 		bool zeroMaskedLanes = true;
182 		*result = Gather(base, *offsets, mask, alignment, zeroMaskedLanes);
183 	}
184 
185 	std::vector<float> buffer(10 + 10 * SIMD::Width);
186 	std::vector<int> offsets(SIMD::Width);
187 
188 	std::vector<float> val(SIMD::Width);
189 
190 	for(int i = 0; i < SIMD::Width; i++)
191 	{
192 		offsets[i] = (3 + 7 * i) * sizeof(float);
193 		val[i] = 13.0f + 17.0f * i;
194 
195 		buffer[offsets[i] / sizeof(float)] = val[i];
196 	}
197 
198 	auto routine = function(testName().c_str());
199 	auto entry = (void (*)(float *, int *, float *))routine->getEntry();
200 
201 	std::vector<float> result(SIMD::Width);
202 	entry(buffer.data(), offsets.data(), result.data());
203 
204 	for(int i = 0; i < SIMD::Width; i++)
205 	{
206 		EXPECT_EQ(result[i], val[i]);
207 	}
208 }
209