Add vmax and vmaxu softrvv vv and vx test Added a different softrvv tests for vmax and vmaxu, since vmax must handle negative values, and vmaxu tests need not have to. Change-Id: I2a7e25677cdbedf954e72b45efdf6b20db2adf22
diff --git a/softrvv/include/softrvv.h b/softrvv/include/softrvv.h index 30326c1..0ab210f 100644 --- a/softrvv/include/softrvv.h +++ b/softrvv/include/softrvv.h
@@ -6,6 +6,7 @@ #include "encoding.h" #include "softrvv_vadd.h" #include "softrvv_vdiv.h" +#include "softrvv_vmax.h" #include "softrvv_vmin.h" #include "softrvv_vmul_vmulh.h" #include "softrvv_vor.h"
diff --git a/softrvv/include/softrvv_vmax.h b/softrvv/include/softrvv_vmax.h new file mode 100644 index 0000000..5ad4352 --- /dev/null +++ b/softrvv/include/softrvv_vmax.h
@@ -0,0 +1,25 @@ +#ifndef SOFTRVV_VMAX_H +#define SOFTRVV_VMAX_H + +#include <stddef.h> +#include <stdint.h> + +namespace softrvv { + +template <typename T> +void vmax_vx(T *dest, T *src1, const T *src2, int32_t avl) { + for (int32_t idx = 0; idx < avl; idx++) { + dest[idx] = (src1[idx] > *src2) ? src1[idx] : *src2; + } +} + +template <typename T> +void vmax_vv(T *dest, T *src1, T *src2, int32_t avl) { + for (int32_t idx = 0; idx < avl; idx++) { + dest[idx] = (src1[idx] > src2[idx]) ? src1[idx] : src2[idx]; + } +} + +} // namespace softrvv + +#endif // SOFTRVV_VMAX_H
diff --git a/softrvv/tests/CMakeLists.txt b/softrvv/tests/CMakeLists.txt index 6fc4a44..221e353 100644 --- a/softrvv/tests/CMakeLists.txt +++ b/softrvv/tests/CMakeLists.txt
@@ -160,3 +160,25 @@ LINKOPTS -Xlinker --defsym=__itcm_length__=128K ) + +vec_cc_test( + NAME + softrvv_vmax + SRCS + softrvv_vmax_test.cpp + DEPS + softrvv + LINKOPTS + -Xlinker --defsym=__itcm_length__=128K +) + +vec_cc_test( + NAME + softrvv_vmaxu + SRCS + softrvv_vmaxu_test.cpp + DEPS + softrvv + LINKOPTS + -Xlinker --defsym=__itcm_length__=128K +)
diff --git a/softrvv/tests/softrvv_vmax_test.cpp b/softrvv/tests/softrvv_vmax_test.cpp new file mode 100644 index 0000000..8b1e179 --- /dev/null +++ b/softrvv/tests/softrvv_vmax_test.cpp
@@ -0,0 +1,48 @@ +#include <riscv_vector.h> +#include <springbok.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include "pw_unit_test/framework.h" +#include "softrvv.h" + +namespace softrvv_vmax_test { +namespace { + +// common to all tests +int32_t src1[] = {-1, 2, 3, 4, 5}; + +// vector test +int32_t src2[] = {5, 4, 3, 2, -1}; + +// scalar register tests +int32_t rs1[] = {-1, 3, 5}; + +}; // namespace +const int32_t kAVL = sizeof(src1) / sizeof(src1[0]); +int32_t dest[kAVL]; + +int32_t ref_vv[] = {5, 4, 3, 4, 5}; + +int32_t ref_vx[3][kAVL] = {{-1, 2, 3, 4, 5}, {3, 3, 3, 4, 5}, {5, 5, 5, 5, 5}}; + +class SoftRvvVmaxTest : public ::testing::Test { + protected: + void SetUp() override { memset(dest, 0, sizeof(dest)); } +}; + +TEST_F(SoftRvvVmaxTest, VV) { + softrvv::vmax_vv<int32_t>(dest, src1, src2, kAVL); + ASSERT_EQ(memcmp(dest, ref_vv, sizeof(dest)), 0); +} + +TEST_F(SoftRvvVmaxTest, VX) { + const int32_t num_vx_tests = sizeof(rs1) / sizeof(rs1[0]); + for (int32_t i = 0; i < num_vx_tests; i++) { + softrvv::vmax_vx<int32_t>(dest, src1, &rs1[i], kAVL); + ASSERT_EQ(memcmp(dest, &ref_vx[i], sizeof(dest)), 0); + } +} + +} // namespace softrvv_vmax_test
diff --git a/softrvv/tests/softrvv_vmaxu_test.cpp b/softrvv/tests/softrvv_vmaxu_test.cpp new file mode 100644 index 0000000..cc7306b --- /dev/null +++ b/softrvv/tests/softrvv_vmaxu_test.cpp
@@ -0,0 +1,48 @@ +#include <riscv_vector.h> +#include <springbok.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include "pw_unit_test/framework.h" +#include "softrvv.h" + +namespace softrvv_vmaxu_test { +namespace { + +// common to all tests +int32_t src1[] = {1, 2, 3, 4, 5}; + +// vector test +int32_t src2[] = {5, 4, 3, 2, 1}; + +// scalar register tests +int32_t rs1[] = {1, 3, 5}; + +}; // namespace +const int32_t kAVL = sizeof(src1) / sizeof(src1[0]); +int32_t dest[kAVL]; + +int32_t ref_vv[] = {5, 4, 3, 4, 5}; + +int32_t ref_vx[3][kAVL] = {{1, 2, 3, 4, 5}, {3, 3, 3, 4, 5}, {5, 5, 5, 5, 5}}; + +class SoftRvvVmaxuTest : public ::testing::Test { + protected: + void SetUp() override { memset(dest, 0, sizeof(dest)); } +}; + +TEST_F(SoftRvvVmaxuTest, VV) { + softrvv::vmax_vv<int32_t>(dest, src1, src2, kAVL); + ASSERT_EQ(memcmp(dest, ref_vv, sizeof(dest)), 0); +} + +TEST_F(SoftRvvVmaxuTest, VX) { + const int32_t num_vx_tests = sizeof(rs1) / sizeof(rs1[0]); + for (int32_t i = 0; i < num_vx_tests; i++) { + softrvv::vmax_vx<int32_t>(dest, src1, &rs1[i], kAVL); + ASSERT_EQ(memcmp(dest, &ref_vx[i], sizeof(dest)), 0); + } +} + +} // namespace softrvv_vmaxu_test
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d30cf2a..687aeb7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt
@@ -196,6 +196,26 @@ vec_cc_generated_test( NAME + vmax + OPFMT + OPIVV + OPIVX + LINKOPTS + -Xlinker --defsym=__itcm_length__=128K +) + +vec_cc_generated_test( + NAME + vmaxu + OPFMT + OPIVV + OPIVX + LINKOPTS + -Xlinker --defsym=__itcm_length__=128K +) + +vec_cc_generated_test( + NAME vsext OPFMT VXUNARY0 @@ -242,15 +262,3 @@ TIMEOUT 40 ) - -vec_cc_test( - NAME - vmax_test - SRCS - vmax_vx_test.cpp - vmax_vv_test.cpp - LINKOPTS - -Xlinker --defsym=__itcm_length__=128K - TIMEOUT - 40 -)
diff --git a/tests/vmax_vv_test.cpp b/tests/vmax_vv_test.cpp deleted file mode 100644 index f4183ec..0000000 --- a/tests/vmax_vv_test.cpp +++ /dev/null
@@ -1,143 +0,0 @@ -#include <limits.h> -#include <riscv_vector.h> -#include <springbok.h> -#include <stdio.h> -#include <stdlib.h> - -#include <bit> -#include <tuple> - -#include "pw_unit_test/framework.h" -#include "test_v_helpers.h" - -namespace vmax_vv_test { -namespace { - -using namespace test_v_helpers; - -uint8_t test_vector_1[MAXVL_BYTES]; -uint8_t test_vector_2[MAXVL_BYTES]; - -template <typename T> -static std::tuple<int, int> vmax_vv_test_setup(VLMUL lmul, int32_t avl) { - // Clear all vector registers - zero_vector_registers(); - - // Initialize test_vector_1 and determine vl, vlmax - uint32_t bw = std::__bit_width(sizeof(T)); - VSEW sew = static_cast<VSEW>(bw - 1); - int vlmax = get_vsetvlmax_intrinsic(sew, lmul); - if (avl > vlmax) { - avl = vlmax; - } - memset(test_vector_1, 0, MAXVL_BYTES); - memset(test_vector_2, 0, MAXVL_BYTES); - int vl = set_vsetvl_intrinsic(sew, lmul, avl); - EXPECT_EQ(avl, vl); - - return std::make_tuple(vlmax, vl); -} - -class VmaxVvTest : public ::testing::Test { - protected: - void SetUp() override { zero_vector_registers(); } - void TearDown() override { zero_vector_registers(); } -}; - -// Below is a non-macro version of the test for more convenient debugging. -// Remove the "DISABLED_" prefix to enable this test for debugging. -TEST_F(VmaxVvTest, DISABLED_vmax_vv_demo) { - for (int i = 0; i < AVL_COUNT; i++) { - int32_t avl = AVLS[i]; - int vlmax; - int vl; - std::tie(vlmax, vl) = vmax_vv_test_setup<int16_t>(VLMUL::LMUL_M1, avl); - if (avl > vlmax) { - continue; - } - int16_t *ptr_vec_1 = reinterpret_cast<int16_t *>(test_vector_1); - int16_t *ptr_vec_2 = reinterpret_cast<int16_t *>(test_vector_2); - - const int16_t start_value = INT16_MAX; - - // set up values for vs2 of vmax.vv - for (int idx = 0; idx < vl; idx++) { - // restrict values to valid int8_t range - ptr_vec_1[idx] = (int16_t)(idx + start_value); - } - - __asm__ volatile("vle16.v v8, (%0)" : : "r"(ptr_vec_1)); - - // set up values for vs2 of vmax.vv - for (int idx = 0; idx < vl; idx++) { - // offset sequence for ptr_vec_2 - ptr_vec_2[idx] = (int16_t)(idx - start_value); - } - - __asm__ volatile("vle16.v v16, (%0)" : : "r"(ptr_vec_2)); - - __asm__ volatile("vmax.vv v24, v16, v8"); - - // emulate operation in C - for (int idx = 0; idx < vl; idx++) { - ptr_vec_1[idx] = - (ptr_vec_1[idx] > ptr_vec_2[idx]) ? ptr_vec_1[idx] : ptr_vec_2[idx]; - } - - __asm__ volatile("vse16.v v24, (%0)" : : "r"(ptr_vec_2)); - assert_vec_elem_eq<int16_t>(vlmax, test_vector_1, test_vector_2); - } -} - -#define DEFINE_TEST_VMAX_VV(_SEW_, _LMUL_, START_VALUE) \ - TEST_F(VmaxVvTest, vmax_vv##_SEW_##m##_LMUL_) { \ - for (int i = 0; i < AVL_COUNT; i++) { \ - int32_t avl = AVLS[i]; \ - int vlmax; \ - int vl; \ - std::tie(vlmax, vl) = \ - vmax_vv_test_setup<int##_SEW_##_t>(VLMUL::LMUL_M##_LMUL_, avl); \ - if (avl > vlmax) { \ - continue; \ - } \ - int##_SEW_##_t *ptr_vec_1 = \ - reinterpret_cast<int##_SEW_##_t *>(test_vector_1); \ - int##_SEW_##_t *ptr_vec_2 = \ - reinterpret_cast<int##_SEW_##_t *>(test_vector_2); \ - const int##_SEW_##_t start_value = START_VALUE; \ - for (int idx = 0; idx < vl; idx++) { \ - ptr_vec_1[idx] = (int##_SEW_##_t)(idx + start_value); \ - } \ - for (int idx = 0; idx < vl; idx++) { \ - ptr_vec_1[idx] = (int##_SEW_##_t)(idx - start_value); \ - } \ - __asm__ volatile("vle" #_SEW_ ".v v8, (%0)" : : "r"(ptr_vec_1)); \ - __asm__ volatile("vle" #_SEW_ ".v v16, (%0)" : : "r"(ptr_vec_2)); \ - __asm__ volatile("vmax.vv v24, v16, v8"); \ - for (int idx = 0; idx < vl; idx++) { \ - ptr_vec_1[idx] = (ptr_vec_1[idx] > ptr_vec_2[idx]) ? ptr_vec_1[idx] \ - : ptr_vec_2[idx]; \ - } \ - __asm__ volatile("vse" #_SEW_ ".v v24, (%0)" : : "r"(ptr_vec_2)); \ - assert_vec_elem_eq<int##_SEW_##_t>(vlmax, test_vector_1, test_vector_2); \ - } \ - } - -// TODO(gkielian): modify macro to permit more than one test per sew/lmul pair -DEFINE_TEST_VMAX_VV(8, 1, INT8_MAX) -DEFINE_TEST_VMAX_VV(8, 2, INT8_MIN) -DEFINE_TEST_VMAX_VV(8, 4, 120) -DEFINE_TEST_VMAX_VV(8, 8, 2) - -DEFINE_TEST_VMAX_VV(16, 1, INT16_MAX) -DEFINE_TEST_VMAX_VV(16, 2, INT16_MIN) -DEFINE_TEST_VMAX_VV(16, 4, 16000) -DEFINE_TEST_VMAX_VV(16, 8, 2) - -DEFINE_TEST_VMAX_VV(32, 1, INT32_MAX) -DEFINE_TEST_VMAX_VV(32, 2, INT32_MIN) -DEFINE_TEST_VMAX_VV(32, 4, 1000000000) -DEFINE_TEST_VMAX_VV(32, 8, 2) - -} // namespace -} // namespace vmax_vv_test
diff --git a/tests/vmax_vx_test.cpp b/tests/vmax_vx_test.cpp deleted file mode 100644 index 3dfed33..0000000 --- a/tests/vmax_vx_test.cpp +++ /dev/null
@@ -1,105 +0,0 @@ -#include <limits.h> -#include <riscv_vector.h> -#include <springbok.h> -#include <stdio.h> -#include <stdlib.h> - -#include <bit> -#include <tuple> - -#include "pw_unit_test/framework.h" -#include "test_v_helpers.h" - -namespace vmax_vx_test { -namespace { - -using namespace test_v_helpers; - -uint8_t test_vector_1[MAXVL_BYTES]; -uint8_t test_vector_2[MAXVL_BYTES]; - -class VmaxVxTest : public ::testing::Test { - protected: - void SetUp() override { zero_vector_registers(); } - void TearDown() override { zero_vector_registers(); } -}; - -// Below is a non-macro version of the test for more convenient debugging. -// Remove the "DISABLED_" prefix to enable this test for debugging. -TEST_F(VmaxVxTest, DISABLED_vmax_vx_demo) { - for (int i = 0; i < AVL_COUNT; i++) { - int32_t avl = AVLS[i]; - int vlmax; - int vl; - std::tie(vlmax, vl) = vector_test_setup<uint8_t>( - VLMUL::LMUL_M1, avl, {test_vector_1, test_vector_2}); - if (avl > vlmax) { - continue; - } - int8_t *ptr_vec_1 = reinterpret_cast<int8_t *>(test_vector_1); - int8_t *ptr_vec_2 = reinterpret_cast<int8_t *>(test_vector_2); - const int8_t test_val = 8; - - for (int idx = 0; idx < vl; idx++) { - ptr_vec_1[idx] = idx; - } - __asm__ volatile("vle8.v v8, (%0)" : : "r"(ptr_vec_1)); - __asm__ volatile("vmax.vx v16, v8, %[RS1]" ::[RS1] "r"(test_val)); - - for (int idx = 0; idx < vl; idx++) { - ptr_vec_1[idx] = (ptr_vec_1[idx] > test_val) ? ptr_vec_1[idx] : test_val; - } - - __asm__ volatile("vse8.v v16, (%0)" : : "r"(ptr_vec_2)); - assert_vec_elem_eq<int8_t>(vlmax, test_vector_1, test_vector_2); - } -} - -#define DEFINE_TEST_VMAX_VX(_SEW_, _LMUL_, TEST_VAL) \ - TEST_F(VmaxVxTest, vmax_vx##_SEW_##m##_LMUL_) { \ - for (int i = 0; i < AVL_COUNT; i++) { \ - int32_t avl = AVLS[i]; \ - int vlmax; \ - int vl; \ - std::tie(vlmax, vl) = vector_test_setup<int##_SEW_##_t>( \ - VLMUL::LMUL_M##_LMUL_, avl, {test_vector_1, test_vector_2}); \ - if (avl > vlmax) { \ - continue; \ - } \ - int##_SEW_##_t *ptr_vec_1 = \ - reinterpret_cast<int##_SEW_##_t *>(test_vector_1); \ - int##_SEW_##_t *ptr_vec_2 = \ - reinterpret_cast<int##_SEW_##_t *>(test_vector_2); \ - const int##_SEW_##_t test_val = TEST_VAL; \ - for (int idx = 0; idx < vl; idx++) { \ - ptr_vec_1[idx] = idx; \ - } \ - __asm__ volatile("vle" #_SEW_ ".v v8, (%0)" : : "r"(ptr_vec_1)); \ - __asm__ volatile("vmax.vx v16, v8, %[RS1]" ::[RS1] "r"(test_val)); \ - for (int idx = 0; idx < vl; idx++) { \ - ptr_vec_1[idx] = \ - (ptr_vec_1[idx] > test_val) ? ptr_vec_1[idx] : test_val; \ - } \ - __asm__ volatile("vse" #_SEW_ ".v v16, (%0)" : : "r"(ptr_vec_2)); \ - assert_vec_elem_eq<int##_SEW_##_t>(vlmax, test_vector_1, test_vector_2); \ - } \ - } - -// TODO(gkielian): modify macro to permit more than one test per sew/lmul pair -DEFINE_TEST_VMAX_VX(8, 1, INT8_MIN) -DEFINE_TEST_VMAX_VX(8, 2, INT8_MAX) -DEFINE_TEST_VMAX_VX(8, 4, -1) -DEFINE_TEST_VMAX_VX(8, 8, 2) - -DEFINE_TEST_VMAX_VX(16, 1, INT16_MIN) -DEFINE_TEST_VMAX_VX(16, 2, INT16_MAX) -DEFINE_TEST_VMAX_VX(16, 4, -1) -DEFINE_TEST_VMAX_VX(16, 8, 2) - -DEFINE_TEST_VMAX_VX(32, 1, INT32_MIN) -DEFINE_TEST_VMAX_VX(32, 2, INT32_MAX) -DEFINE_TEST_VMAX_VX(32, 4, -1) -DEFINE_TEST_VMAX_VX(32, 8, 2) - -} // namespace -} // namespace vmax_vx_test