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