209 lines
4.7 KiB
C++
209 lines
4.7 KiB
C++
// 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]);
|
|
}
|
|
}
|