blob: d7f9824a17310e64fd9df8bfb1de4905b7b075fb [file] [log] [blame]
/*
* Copyright 2023 Google LLC
*
* 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 <cstdio>
#include "tests/kelvin_isa/kelvin_test.h"
#define vacc_v(T, Vd, Vs, Vt) \
{ \
if (sizeof(T) == 2) { \
if (std::is_signed<T>::value) \
vacc_h_vv(Vd, Vs, Vt); \
else \
vacc_h_u_vv(Vd, Vs, Vt); \
} \
if (sizeof(T) == 4) { \
if (std::is_signed<T>::value) \
vacc_w_vv(Vd, Vs, Vt); \
else \
vacc_w_u_vv(Vd, Vs, Vt); \
} \
}
#define vacc_v(T, Vd, Vs, Vt) \
{ \
if (sizeof(T) == 2) { \
if (std::is_signed<T>::value) \
vacc_h_vv(Vd, Vs, Vt); \
else \
vacc_h_u_vv(Vd, Vs, Vt); \
} \
if (sizeof(T) == 4) { \
if (std::is_signed<T>::value) \
vacc_w_vv(Vd, Vs, Vt); \
else \
vacc_w_u_vv(Vd, Vs, Vt); \
} \
}
#define vacc_v_m(T, Vd, Vs, Vt) \
{ \
if (sizeof(T) == 2) { \
if (std::is_signed<T>::value) \
vacc_h_vv_m(Vd, Vs, Vt); \
else \
vacc_h_u_vv_m(Vd, Vs, Vt); \
} \
if (sizeof(T) == 4) { \
if (std::is_signed<T>::value) \
vacc_w_vv_m(Vd, Vs, Vt); \
else \
vacc_w_u_vv_m(Vd, Vs, Vt); \
} \
}
template <typename T1, typename T2>
static void test_vacc() {
static_assert(sizeof(T1) == 2 * sizeof(T2));
static_assert(std::is_signed<T1>::value == std::is_signed<T2>::value);
constexpr int n = sizeof(T1);
int lanes;
getmaxvl(T1, lanes);
T1 acc[2][lanes] __attribute__((aligned(64)));
T1 dut[2][lanes] __attribute__((aligned(64)));
T1 ref[2][lanes] __attribute__((aligned(64)));
T2 inp[lanes * 2] __attribute__((aligned(64)));
for (int i = 0; i < lanes; ++i) {
acc[0][i] = (0x40 << (8 * (n - 1)));
acc[1][i] = (0x80 << (8 * (n - 1)));
}
for (int j = 0; j < lanes * 2; ++j) {
inp[j] = -lanes + j;
}
for (int i = 0; i < lanes; ++i) {
ref[0][i] = acc[0][i] + inp[2 * i + 0];
ref[1][i] = acc[1][i] + inp[2 * i + 1];
}
vld_x(T1, v0, acc[0]);
vld_x(T1, v1, acc[1]);
vld_x(T2, v8, inp);
vacc_v(T1, v4, v0, v8);
vst_x(T1, v4, dut[0]);
vst_x(T1, v5, dut[1]);
for (int i = 0; i < lanes; ++i) {
if (ref[0][i] != dut[0][i] || ref[1][i] != dut[1][i]) {
printf("**error vacc[%d]\n", i);
exit(-1);
}
}
}
template <typename T1, typename T2>
static void test_vacc_m() {
static_assert(sizeof(T1) == 2 * sizeof(T2));
static_assert(std::is_signed<T1>::value == std::is_signed<T2>::value);
constexpr int n = sizeof(T1);
int lanes;
getmaxvl_m(T1, lanes);
T1 acc[2][lanes] __attribute__((aligned(64)));
T1 dut[2][lanes] __attribute__((aligned(64)));
T1 ref[2][lanes] __attribute__((aligned(64)));
T2 inp[lanes * 2] __attribute__((aligned(64)));
for (int i = 0; i < lanes; ++i) {
acc[0][i] = (0x40 << (8 * (n - 1)));
acc[1][i] = (0x80 << (8 * (n - 1)));
}
for (int j = 0; j < lanes * 2; ++j) {
inp[j] = -lanes + j;
}
for (int i = 0; i < lanes; ++i) {
ref[0][i] = acc[0][i] + inp[2 * i + 0];
ref[1][i] = acc[1][i] + inp[2 * i + 1];
}
vld_x_m(T1, v0, acc[0]);
vld_x_m(T1, v4, acc[1]);
vld_x_m(T2, v16, inp);
vacc_v_m(T1, v8, v0, v16);
vst_x_m(T1, v8, dut[0]);
vst_x_m(T1, v12, dut[1]);
for (int i = 0; i < lanes; ++i) {
if (ref[0][i] != dut[0][i] || ref[1][i] != dut[1][i]) {
printf("**error vacc_m[%d]\n", i);
// printf("%x %x : %x %x\n", ref[0][i], dut[0][i], ref[1][i], dut[1][i]);
exit(-1);
}
}
}
int main() {
test_vacc<int16_t, int8_t>();
test_vacc<uint16_t, uint8_t>();
test_vacc<int32_t, int16_t>();
test_vacc<uint32_t, uint16_t>();
test_vacc_m<int16_t, int8_t>();
test_vacc_m<uint16_t, uint8_t>();
test_vacc_m<int32_t, int16_t>();
test_vacc_m<uint32_t, uint16_t>();
return 0;
}