blob: a4ebe8efd27e58b9b178eabedb1acd13aa08ca1e [file] [log] [blame]
// 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]);
}
}