Add support for vmul and vmulh.

* Add softrvv vmul, vmulh implementations and tests.
* Add vmul, vmulh vector instruction tests.

Change-Id: Ib07351314112e7670f969cac2cf626aee4408cbf
diff --git a/softrvv/include/softrvv.h b/softrvv/include/softrvv.h
index 0edbf3c..596341f 100644
--- a/softrvv/include/softrvv.h
+++ b/softrvv/include/softrvv.h
@@ -6,11 +6,11 @@
 #include "encoding.h"
 #include "softrvv_vadd.h"
 #include "softrvv_vmin.h"
+#include "softrvv_vmul_vmulh.h"
+#include "softrvv_vsext_vzext.h"
 #include "softrvv_vsub.h"
 #include "softrvv_vwadd.h"
 #include "softrvv_vwsub.h"
-#include "softrvv_vsext_vzext.h"
-
 
 namespace softrvv {
 
diff --git a/softrvv/include/softrvv_vmul_vmulh.h b/softrvv/include/softrvv_vmul_vmulh.h
new file mode 100644
index 0000000..1e5a816
--- /dev/null
+++ b/softrvv/include/softrvv_vmul_vmulh.h
@@ -0,0 +1,44 @@
+#ifndef SOFTRVV_VMUL_H
+#define SOFTRVV_VMUL_H
+
+#include <stddef.h>
+
+namespace softrvv {
+
+template <typename T>
+void vmul_vx(T *dest, T *src1, const T *src2, int32_t avl) {
+  for (int32_t idx = 0; idx < avl; idx++) {
+    dest[idx] = src1[idx] * *src2;
+  }
+}
+
+template <typename T>
+void vmul_vv(T *dest, T *src1, T *src2, int32_t avl) {
+  for (int32_t idx = 0; idx < avl; idx++) {
+    dest[idx] = src1[idx] * src2[idx];
+  }
+}
+
+template <typename T>
+void vmulh_vx(T *dest, T *src1, const T *src2, int32_t avl) {
+  for (int32_t idx = 0; idx < avl; idx++) {
+    // TODO(b/197705521) find a better way to promote T to larger type
+    int64_t temp =
+        static_cast<int64_t>(src1[idx]) * static_cast<int64_t>(*src2);
+    dest[idx] = static_cast<T>(temp >> (sizeof(T) * 8));
+  }
+}
+
+template <typename T>
+void vmulh_vv(T *dest, T *src1, T *src2, int32_t avl) {
+  for (int32_t idx = 0; idx < avl; idx++) {
+    // TODO(b/197705521) find a better way to promote T to larger type
+    int64_t temp =
+        static_cast<int64_t>(src1[idx]) * static_cast<int64_t>(src2[idx]);
+    dest[idx] = static_cast<T>(temp >> (sizeof(T) * 8));
+  }
+}
+
+}  // namespace softrvv
+
+#endif  // SOFTRVV_VMUL_H
diff --git a/softrvv/tests/CMakeLists.txt b/softrvv/tests/CMakeLists.txt
index edb6575..0638773 100644
--- a/softrvv/tests/CMakeLists.txt
+++ b/softrvv/tests/CMakeLists.txt
@@ -108,3 +108,21 @@
   LINKOPTS
    -Xlinker --defsym=__itcm_length__=128K
 )
+
+softrvv_vec_cc_generated_test(
+  NAME
+    vmul
+  TEMPLATE
+    softrvv_vmul_test.tpl.cpp
+  LINKOPTS
+   -Xlinker --defsym=__itcm_length__=128K
+)
+
+softrvv_vec_cc_generated_test(
+  NAME
+    vmulh
+  TEMPLATE
+    softrvv_vmulh_test.tpl.cpp
+  LINKOPTS
+   -Xlinker --defsym=__itcm_length__=128K
+)
diff --git a/softrvv/tests/templates/softrvv_vmul_test.tpl.cpp b/softrvv/tests/templates/softrvv_vmul_test.tpl.cpp
new file mode 100644
index 0000000..e9a1832
--- /dev/null
+++ b/softrvv/tests/templates/softrvv_vmul_test.tpl.cpp
@@ -0,0 +1,20 @@
+<%inherit file="base.tpl.cpp"/>\
+<%namespace name="tests" file="opivv_opivx_test.tpl.cpp"/>
+<%
+import numpy as np
+# Generate test vectors using python
+N = 5
+ii32 = np.iinfo(np.int32)
+src1_data =  np.random.randint(ii32.min, ii32.max, N).astype(np.int32)
+src2_data = np.random.randint(ii32.min, ii32.max, N).astype(np.int32)
+rs1 = np.int32(np.random.randint(ii32.min, ii32.max))
+ref_vv_data = src1_data * src2_data
+ref_vx_data = src1_data * rs1
+
+# Convert test vectors to strings for array initialization
+src1 = parent.module.to_carr_str(src1_data)
+src2 = parent.module.to_carr_str(src2_data)
+ref_vv = parent.module.to_carr_str(ref_vv_data)
+ref_vx = parent.module.to_carr_str(ref_vx_data)
+%>\
+${tests.test_opivv_opivx("int32_t", op, src1, src2, rs1, ref_vv, ref_vx)}
diff --git a/softrvv/tests/templates/softrvv_vmulh_test.tpl.cpp b/softrvv/tests/templates/softrvv_vmulh_test.tpl.cpp
new file mode 100644
index 0000000..c4d82a8
--- /dev/null
+++ b/softrvv/tests/templates/softrvv_vmulh_test.tpl.cpp
@@ -0,0 +1,22 @@
+<%inherit file="base.tpl.cpp"/>\
+<%namespace name="tests" file="opivv_opivx_test.tpl.cpp"/>
+<%
+import numpy as np
+# Generate test vectors using python
+N = 5
+ii32 = np.iinfo(np.int32)
+src1_data =  np.random.randint(ii32.min, ii32.max, N).astype(np.int32)
+src2_data = np.random.randint(ii32.min, ii32.max, N).astype(np.int32)
+rs1 = np.int32(np.random.randint(ii32.min, ii32.max))
+ref_vv_data = np.right_shift(
+    src1_data.astype(np.int64) * src2_data.astype(np.int64), 32).astype(np.int32)
+ref_vx_data = np.right_shift(
+    src1_data.astype(np.int64) * rs1, 32).astype(np.int32)
+
+# Convert test vectors to strings for array initialization
+src1 = parent.module.to_carr_str(src1_data)
+src2 = parent.module.to_carr_str(src2_data)
+ref_vv = parent.module.to_carr_str(ref_vv_data)
+ref_vx = parent.module.to_carr_str(ref_vx_data)
+%>
+${tests.test_opivv_opivx("int32_t", op, src1, src2, rs1, ref_vv, ref_vx)}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 1ec4a36..effcafe 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -64,6 +64,36 @@
 
 vec_cc_generated_test(
   NAME
+    vmul
+  OPFMT
+    OPIVV
+    OPIVX
+  LINKOPTS
+   -Xlinker --defsym=__itcm_length__=128K
+)
+
+vec_cc_generated_test(
+  NAME
+    vmulh
+  OPFMT
+    OPIVV
+    OPIVX
+  LINKOPTS
+   -Xlinker --defsym=__itcm_length__=128K
+)
+
+vec_cc_generated_test(
+  NAME
+    vmulhu
+  OPFMT
+    OPIVV
+    OPIVX
+  LINKOPTS
+   -Xlinker --defsym=__itcm_length__=128K
+)
+
+vec_cc_generated_test(
+  NAME
     vwadd
   OPFMT
     OPIVV