// 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 function; { Pointer r = Pointer(function.Arg<0>()); Pointer a = Pointer(function.Arg<1>()); Pointer b = Pointer(function.Arg<2>()); For(Int i = 0, i < arrayLength, i += SIMD::Width) { SIMD::Int x = *Pointer(&a[i]); SIMD::Int y = *Pointer(&b[i]); SIMD::Int z = x + y; *Pointer(&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 function; { Pointer r = Pointer(function.Arg<0>()); Int a = function.Arg<1>(); SIMD::Int x = a; *Pointer(r) = x; } auto routine = function(testName().c_str()); std::vector 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 function; { Pointer r = Pointer(function.Arg<0>()); Pointer a = Pointer(function.Arg<1>()); SIMD::Int x = *Pointer(a); SIMD::Int y = *Pointer(r); x -= y; for(int i = 0; i < SIMD::Width / 4; i++) { y = Insert128(y, Extract128(x, i) << (i + 1), i); } *Pointer(r) = y; } auto routine = function(testName().c_str()); std::vector r(SIMD::Width); std::vector 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 base, Pointer val, Pointer offsets)> function; { Pointer base = function.Arg<0>(); Pointer val = function.Arg<1>(); Pointer offsets = function.Arg<2>(); SIMD::Int mask = ~0; unsigned int alignment = 1; Scatter(base, *val, *offsets, mask, alignment); } std::vector buffer(10 + 10 * SIMD::Width); std::vector offsets(SIMD::Width); std::vector 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 base, Pointer offsets, Pointer result)> function; { Pointer base = function.Arg<0>(); Pointer offsets = function.Arg<1>(); Pointer result = function.Arg<2>(); SIMD::Int mask = ~0; unsigned int alignment = 1; bool zeroMaskedLanes = true; *result = Gather(base, *offsets, mask, alignment, zeroMaskedLanes); } std::vector buffer(10 + 10 * SIMD::Width); std::vector offsets(SIMD::Width); std::vector 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 result(SIMD::Width); entry(buffer.data(), offsets.data(), result.data()); for(int i = 0; i < SIMD::Width; i++) { EXPECT_EQ(result[i], val[i]); } }