|  | // Copyright 2022 The SwiftShader Authors. All Rights Reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //    http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #include "Reactor.hpp" | 
|  | #include "SIMD.hpp" | 
|  |  | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | using namespace rr; | 
|  |  | 
|  | static std::string testName() | 
|  | { | 
|  | auto info = ::testing::UnitTest::GetInstance()->current_test_info(); | 
|  | return std::string{ info->test_suite_name() } + "_" + info->name(); | 
|  | } | 
|  |  | 
|  | TEST(ReactorSIMD, Add) | 
|  | { | 
|  | ASSERT_GE(SIMD::Width, 4); | 
|  |  | 
|  | constexpr int arrayLength = 1024; | 
|  |  | 
|  | FunctionT<void(int *, int *, int *)> function; | 
|  | { | 
|  | Pointer<Int> r = Pointer<Int>(function.Arg<0>()); | 
|  | Pointer<Int> a = Pointer<Int>(function.Arg<1>()); | 
|  | Pointer<Int> b = Pointer<Int>(function.Arg<2>()); | 
|  |  | 
|  | For(Int i = 0, i < arrayLength, i += SIMD::Width) | 
|  | { | 
|  | SIMD::Int x = *Pointer<SIMD::Int>(&a[i]); | 
|  | SIMD::Int y = *Pointer<SIMD::Int>(&b[i]); | 
|  |  | 
|  | SIMD::Int z = x + y; | 
|  |  | 
|  | *Pointer<SIMD::Int>(&r[i]) = z; | 
|  | } | 
|  | } | 
|  |  | 
|  | auto routine = function(testName().c_str()); | 
|  |  | 
|  | int r[arrayLength] = {}; | 
|  | int a[arrayLength]; | 
|  | int b[arrayLength]; | 
|  |  | 
|  | for(int i = 0; i < arrayLength; i++) | 
|  | { | 
|  | a[i] = i; | 
|  | b[i] = arrayLength + i; | 
|  | } | 
|  |  | 
|  | routine(r, a, b); | 
|  |  | 
|  | for(int i = 0; i < arrayLength; i++) | 
|  | { | 
|  | ASSERT_EQ(r[i], arrayLength + 2 * i); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(ReactorSIMD, Broadcast) | 
|  | { | 
|  | FunctionT<void(int *, int)> function; | 
|  | { | 
|  | Pointer<Int> r = Pointer<Int>(function.Arg<0>()); | 
|  | Int a = function.Arg<1>(); | 
|  |  | 
|  | SIMD::Int x = a; | 
|  |  | 
|  | *Pointer<SIMD::Int>(r) = x; | 
|  | } | 
|  |  | 
|  | auto routine = function(testName().c_str()); | 
|  |  | 
|  | std::vector<int> r(SIMD::Width); | 
|  |  | 
|  | for(int a = -2; a <= 2; a++) | 
|  | { | 
|  | routine(r.data(), a); | 
|  |  | 
|  | for(int i = 0; i < SIMD::Width; i++) | 
|  | { | 
|  | ASSERT_EQ(r[i], a); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(ReactorSIMD, InsertExtract128) | 
|  | { | 
|  | FunctionT<void(int *, int *)> function; | 
|  | { | 
|  | Pointer<Int> r = Pointer<Int>(function.Arg<0>()); | 
|  | Pointer<Int> a = Pointer<Int>(function.Arg<1>()); | 
|  |  | 
|  | SIMD::Int x = *Pointer<SIMD::Int>(a); | 
|  | SIMD::Int y = *Pointer<SIMD::Int>(r); | 
|  |  | 
|  | x -= y; | 
|  |  | 
|  | for(int i = 0; i < SIMD::Width / 4; i++) | 
|  | { | 
|  | y = Insert128(y, Extract128(x, i) << (i + 1), i); | 
|  | } | 
|  |  | 
|  | *Pointer<SIMD::Int>(r) = y; | 
|  | } | 
|  |  | 
|  | auto routine = function(testName().c_str()); | 
|  |  | 
|  | std::vector<int> r(SIMD::Width); | 
|  | std::vector<int> a(SIMD::Width); | 
|  |  | 
|  | for(int i = 0; i < SIMD::Width; i++) | 
|  | { | 
|  | r[i] = 0; | 
|  | a[i] = 1 + i; | 
|  | } | 
|  |  | 
|  | routine(r.data(), a.data()); | 
|  |  | 
|  | for(int i = 0; i < SIMD::Width; i++) | 
|  | { | 
|  | ASSERT_EQ(r[i], a[i] << (i / 4 + 1)); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(ReactorSIMD, Intrinsics_Scatter) | 
|  | { | 
|  | Function<Void(Pointer<Float> base, Pointer<SIMD::Float> val, Pointer<SIMD::Int> offsets)> function; | 
|  | { | 
|  | Pointer<Float> base = function.Arg<0>(); | 
|  | Pointer<SIMD::Float> val = function.Arg<1>(); | 
|  | Pointer<SIMD::Int> offsets = function.Arg<2>(); | 
|  |  | 
|  | SIMD::Int mask = ~0; | 
|  | unsigned int alignment = 1; | 
|  | Scatter(base, *val, *offsets, mask, alignment); | 
|  | } | 
|  |  | 
|  | std::vector<float> buffer(10 + 10 * SIMD::Width); | 
|  | std::vector<int> offsets(SIMD::Width); | 
|  | std::vector<float> val(SIMD::Width); | 
|  |  | 
|  | for(int i = 0; i < SIMD::Width; i++) | 
|  | { | 
|  | offsets[i] = (3 + 7 * i) * sizeof(float); | 
|  | val[i] = 13.0f + 17.0f * i; | 
|  | } | 
|  |  | 
|  | auto routine = function(testName().c_str()); | 
|  | auto entry = (void (*)(float *, float *, int *))routine->getEntry(); | 
|  |  | 
|  | entry(buffer.data(), val.data(), offsets.data()); | 
|  |  | 
|  | for(int i = 0; i < SIMD::Width; i++) | 
|  | { | 
|  | EXPECT_EQ(buffer[offsets[i] / sizeof(float)], val[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(ReactorSIMD, Intrinsics_Gather) | 
|  | { | 
|  | Function<Void(Pointer<Float> base, Pointer<SIMD::Int> offsets, Pointer<SIMD::Float> result)> function; | 
|  | { | 
|  | Pointer<Float> base = function.Arg<0>(); | 
|  | Pointer<SIMD::Int> offsets = function.Arg<1>(); | 
|  | Pointer<SIMD::Float> result = function.Arg<2>(); | 
|  |  | 
|  | SIMD::Int mask = ~0; | 
|  | unsigned int alignment = 1; | 
|  | bool zeroMaskedLanes = true; | 
|  | *result = Gather(base, *offsets, mask, alignment, zeroMaskedLanes); | 
|  | } | 
|  |  | 
|  | std::vector<float> buffer(10 + 10 * SIMD::Width); | 
|  | std::vector<int> offsets(SIMD::Width); | 
|  |  | 
|  | std::vector<float> val(SIMD::Width); | 
|  |  | 
|  | for(int i = 0; i < SIMD::Width; i++) | 
|  | { | 
|  | offsets[i] = (3 + 7 * i) * sizeof(float); | 
|  | val[i] = 13.0f + 17.0f * i; | 
|  |  | 
|  | buffer[offsets[i] / sizeof(float)] = val[i]; | 
|  | } | 
|  |  | 
|  | auto routine = function(testName().c_str()); | 
|  | auto entry = (void (*)(float *, int *, float *))routine->getEntry(); | 
|  |  | 
|  | std::vector<float> result(SIMD::Width); | 
|  | entry(buffer.data(), offsets.data(), result.data()); | 
|  |  | 
|  | for(int i = 0; i < SIMD::Width; i++) | 
|  | { | 
|  | EXPECT_EQ(result[i], val[i]); | 
|  | } | 
|  | } |