Merge branch 'master' of https://spacebeaker.googlesource.com/shodan/sw/vec into vector_test
Change-Id: I13979c48cda162b959fecc8b97b9df0b5775ba99
diff --git a/scripts/vec_test_helpers/__init__.py b/scripts/vec_test_helpers/__init__.py
index 87f457e..4aa284e 100644
--- a/scripts/vec_test_helpers/__init__.py
+++ b/scripts/vec_test_helpers/__init__.py
@@ -14,6 +14,7 @@
VECTOR = enum.auto()
SCALAR = enum.auto()
IMMEDIATE = enum.auto()
+ FLOATSCALAR = enum.auto()
class OperandWidth(enum.Enum):
"""RISC-V V operand width type option."""
@@ -37,6 +38,11 @@
OperandWidth.WIDENING: "vi",
OperandWidth.NARROWING: "wi",
},
+ OperandType.FLOATSCALAR : {
+ OperandWidth.STANDARD: "vf",
+ OperandWidth.WIDENING: "vf",
+ OperandWidth.NARROWING: "wf",
+ },
}
"""Helper class for providing params for use in templates"""
@@ -52,12 +58,14 @@
8:np.uint8,
16:np.uint16,
32:np.uint32}
+ self.float_np_types = {
+ 32:np.float32}
@property
def op_code(self):
"""Return the op_code."""
if self._op_code is None:
- raise ValueError("SEW was not set.")
+ raise ValueError("OP CODE was not set.")
return self._op_code
@op_code.setter
@@ -65,6 +73,10 @@
"""Set the op_code"""
self._op_code = value
+ def is_floating(self):
+ """check if a particular op_code is a floating type."""
+ return self.op_code[1] == 'f'
+
@property
def sew(self):
"""Return the selected element width."""
@@ -75,52 +87,68 @@
@sew.setter
def sew(self, value):
"""Set the selected element width."""
+ if self.is_floating():
+ if not (value == 32):
+ raise ValueError("Invalid SEW")
if not value in (8, 16, 32):
raise ValueError("Invalid SEW")
self._sew = value
def is_widening(self):
"""Check if a particular op_code is a widening type."""
+ if self.is_floating():
+ raise ValueError("Widening is not supported with this template for floating point values")
return self.op_code[1] == 'w'
def is_narrowing(self):
"""Check if a particular op_code is a narrowing type."""
+ if self.is_floating():
+ raise ValueError("Narrowing is not supported with this template for floating point values")
return self.op_code[1] == 'n'
def is_destination_mask_register(self):
"""Check if a particular op_code has a mask output."""
+ if self.is_floating():
+ return False
int_comparison_ops = ('vmseq', 'vmsne', 'vmsltu', 'vmsleu', 'vmsle', 'vmsgtu', 'vmsgt')
return self.op_code in int_comparison_ops
def is_unsigned(self):
"""Check if a particular op_code is a unsigned type."""
+ if self.is_floating():
+ raise ValueError("Invalid unsigned type op code")
return self.op_code[-1] == 'u'
def get_sews(self):
"""Given an op_code return a list of valid element widths."""
+ if self.is_floating():
+ return [32]
+
if self.is_widening() or self.is_narrowing():
return [8, 16]
return [8, 16, 32]
def get_sew_sizes(self):
"""Return size of types."""
+ """imm is not used for floating point op codes."""
dest_sew = self.sew
src2_sew = self.sew
src1_sew = self.sew
imm_sew = self.sew
- if self.is_narrowing():
+ if (not self.is_floating()) and self.is_narrowing():
src2_sew = self.sew * 2
- elif self.is_widening():
+ elif (not self.is_floating()) and self.is_widening():
dest_sew = self.sew * 2
return dest_sew, src2_sew, src1_sew, imm_sew
def get_var_types(self):
"""Return types for an op_code and element width."""
+ """imm_type won't be used for floating point values."""
VarTypes = collections.namedtuple(
"VarTypes",
('dest_type', 'src2_type', 'src1_type', 'imm_type'))
- type_fmt = "%sint%d_t"
- sign_type = "u" if self.is_unsigned() or self.force_unsigned else ""
+ type_fmt = "%sfloat%d_t" if self.is_floating() else "%sint%d_t"
+ sign_type = "u" if (not self.is_floating()) and (self.is_unsigned() or self.force_unsigned) else ""
dest_sew, src2_sew, src1_sew, imm_sew = self.get_sew_sizes()
dest_type = type_fmt % (sign_type, dest_sew)
src1_type = type_fmt % (sign_type, src1_sew)
@@ -132,16 +160,18 @@
def get_mnemonic(self, operand_type):
"""Generate the correct mnemonic given a opcode and operand type."""
operand_width = self.OperandWidth.STANDARD
- if self.is_narrowing():
+ if (not self.is_floating()) and self.is_narrowing():
operand_width = self.OperandWidth.NARROWING
- elif self.is_widening():
+ elif (not self.is_floating()) and self.is_widening():
operand_width = self.OperandWidth.WIDENING
+ if self.is_floating() and operand_type == self.OperandType.SCALAR:
+ operand_type = self.OperandType.FLOATSCALAR
op_suffix = self.mnemonic_suffix[operand_type][operand_width]
return "%s.%s" % (self.op_code, op_suffix)
def get_lmuls(self):
"""Given an op_code return an iterable of valid lmuls."""
- if self.is_widening() or self.is_narrowing():
+ if (not self.is_floating()) and (self.is_widening() or self.is_narrowing()):
return [1, 2, 4]
return [1, 2, 4, 8]
@@ -154,16 +184,20 @@
def get_softrvv_template_data_type(self):
"""Return types """
var_types = self.get_var_types()
- if self.is_narrowing() or self.is_widening():
+ if (not self.is_floating()) and (self.is_narrowing() or self.is_widening()):
return "%s, %s" % (var_types.dest_type, var_types.src2_type)
return var_types.src1_type
def get_ref_opcode(self):
"""Return the name of the reference code in the softrvv library."""
+ if self.is_floating():
+ return self.op_code
return self.op_code[:-1] if self.is_unsigned() else self.op_code
def get_imms(self):
"""Return a list of valid immediate values for a op code."""
+ if self.is_floating():
+ raise ValueError("imm is not available.")
if self.op_code in ['vsll', 'vsrl', 'vsra', 'vnsrl', 'vnsra']:
# Left and right shift immediates must be [0,31]
return np.linspace(0, 31, 8, dtype=np.int32)
@@ -172,6 +206,8 @@
def get_np_dest_type(self):
"""Return numpy type for destination."""
+ if self.is_floating():
+ return self.float_np_types[self.sew]
if self.force_unsigned:
types = self.unsigned_np_types
else:
@@ -182,6 +218,8 @@
def get_np_src1_type(self):
"""Return numpy type for src1."""
+ if self.is_floating():
+ return self.float_np_types[self.sew]
if self.force_unsigned:
types = self.unsigned_np_types
else:
@@ -190,6 +228,8 @@
def get_np_src2_type(self):
"""Return numpy type for src2."""
+ if self.is_floating():
+ return self.float_np_types[self.sew]
if self.force_unsigned:
types = self.unsigned_np_types
else:
@@ -202,12 +242,28 @@
"""Return test inputs."""
src1_np_type = self.get_np_src1_type()
src2_np_type = self.get_np_src2_type()
+ src2_np_type = self.get_np_src2_type()
+ """Return test inputs for floating points."""
+ if self.is_floating():
+ type_info = np.finfo(src1_np_type)
+ src1_data = np.random.uniform(
+ type_info.min/2.0, type_info.max/2.0, n).astype(src1_np_type)
+ rs1 = self.get_np_src1_type()(np.random.uniform(
+ type_info.min/2.0, type_info.max/2.0))
+ type_info = np.finfo(src2_np_type)
+ src2_data = np.random.uniform(
+ type_info.min/2.0, type_info.max/2.0, n).astype(src2_np_type)
+ if not allow_zero:
+ src2_data[src2_data==0] = 1
+ rs1 = 1.0 if rs1 == 0.0 else rs1
+ return src2_data, src1_data, rs1
+
+ """Return test inputs for integers."""
type_info = np.iinfo(src1_np_type)
src1_data = np.random.randint(
type_info.min, type_info.max, n).astype(src1_np_type)
rs1 = self.get_np_src1_type()(np.random.randint(
type_info.min, type_info.max))
- src2_np_type = self.get_np_src2_type()
type_info = np.iinfo(src2_np_type)
src2_data = np.random.randint(
type_info.min, type_info.max, n).astype(src2_np_type)
@@ -217,12 +273,13 @@
return src2_data, src1_data, rs1
def pack_dest_mask(self, values):
- """Pack values into a single destination register."""
- dest_type = self.get_np_dest_type()
- return np.packbits(dest_type(values), bitorder='little')
+ """Pack values into a single destination register."""
+ dest_type = self.get_np_dest_type()
+ return np.packbits(dest_type(values), bitorder='little')
def cast_to_unsigned(arr):
"""Cast a signed array to an unsigned array."""
+ """This should not be called with floating point values."""
udtypes = {np.int8:np.uint8,
np.int16:np.uint16,
np.int32:np.uint32,
diff --git a/softrvv/include/softrvv.h b/softrvv/include/softrvv.h
index d82e7a0..1046aba 100644
--- a/softrvv/include/softrvv.h
+++ b/softrvv/include/softrvv.h
@@ -31,6 +31,9 @@
#include "softrvv_vwsub.h"
#include "softrvv_vxor.h"
+#include "softrvv_vfadd.h"
+#include "softrvv_vfsub.h"
+
namespace softrvv {
const uint32_t MSTATUS_VS_FS_ENABLE_BIT =
diff --git a/softrvv/include/softrvv_vfadd.h b/softrvv/include/softrvv_vfadd.h
new file mode 100644
index 0000000..86009c8
--- /dev/null
+++ b/softrvv/include/softrvv_vfadd.h
@@ -0,0 +1,24 @@
+#ifndef SOFTRVV_VFADD_H
+#define SOFTRVV_VFADD_H
+
+#include <stddef.h>
+
+namespace softrvv {
+
+template <typename T>
+void vfadd_vf(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 vfadd_vv(T *dest, T *src1, T *src2, int32_t avl) {
+ for (int32_t idx = 0; idx < avl; idx++) {
+ dest[idx] = src1[idx] + src2[idx];
+ }
+}
+
+} // namespace softrvv
+
+#endif // SOFTRVV_VFADD_H
diff --git a/softrvv/include/softrvv_vfsub.h b/softrvv/include/softrvv_vfsub.h
new file mode 100644
index 0000000..eea2f26
--- /dev/null
+++ b/softrvv/include/softrvv_vfsub.h
@@ -0,0 +1,31 @@
+#ifndef SOFTRVV_VFSUB_H
+#define SOFTRVV_VFSUB_H
+
+#include <stddef.h>
+
+namespace softrvv {
+
+template <typename T>
+void vfsub_vf(T *dest, T *src1, const T *src2, int32_t avl) {
+ for (int idx = 0; idx < avl; idx++) {
+ dest[idx] = src1[idx] - *src2;
+ }
+}
+
+template <typename T>
+void vfsub_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 vfrsub_vx(T *dest, T *src1, const T *src2, int32_t avl) {
+ for (int32_t idx = 0; idx < avl; idx++) {
+ dest[idx] = *src2 - src1[idx];
+ }
+}
+
+} // namespace softrvv
+
+#endif // SOFTRVV_VFSUB_H
diff --git a/softrvv/tests/CMakeLists.txt b/softrvv/tests/CMakeLists.txt
index 62cbc9a..289f74e 100644
--- a/softrvv/tests/CMakeLists.txt
+++ b/softrvv/tests/CMakeLists.txt
@@ -100,6 +100,24 @@
softrvv_vec_cc_generated_test(
NAME
+ vfadd
+ TEMPLATE
+ softrvv_vfadd_test.tpl.cpp
+ LINKOPTS
+ -Xlinker --defsym=__itcm_length__=128K
+)
+
+softrvv_vec_cc_generated_test(
+ NAME
+ vfsub
+ TEMPLATE
+ softrvv_vfsub_test.tpl.cpp
+ LINKOPTS
+ -Xlinker --defsym=__itcm_length__=128K
+)
+
+softrvv_vec_cc_generated_test(
+ NAME
vadd
TEMPLATE
softrvv_vadd_test.tpl.cpp
diff --git a/softrvv/tests/templates/base.tpl.cpp b/softrvv/tests/templates/base.tpl.cpp
index 586cfff..9fc3bfa 100644
--- a/softrvv/tests/templates/base.tpl.cpp
+++ b/softrvv/tests/templates/base.tpl.cpp
@@ -1,16 +1,3 @@
-<%!
-import numpy as np
-
-def get_test_inputs(dtype, N, allow_zero=True):
- ii32 = np.iinfo(dtype)
- src1_data = np.random.randint(ii32.min, ii32.max, N).astype(dtype)
- src2_data = np.random.randint(ii32.min, ii32.max, N).astype(dtype)
- rs1 = dtype(np.random.randint(ii32.min, ii32.max))
- if not allow_zero:
- src2_data[src2_data==0] = 1
- rs1 = 1 if rs1 == 0 else rs1
- return src1_data, src2_data, rs1
-%>
/* File is auto-generated. */
#include <riscv_vector.h>
#include <springbok.h>
diff --git a/softrvv/tests/templates/opivf_test.tpl.cpp b/softrvv/tests/templates/opivf_test.tpl.cpp
new file mode 100644
index 0000000..87c04c1
--- /dev/null
+++ b/softrvv/tests/templates/opivf_test.tpl.cpp
@@ -0,0 +1,52 @@
+<%!
+import vec_test_helpers
+%>\
+<%def name="test_opivf(template_helper, src2, rs1, ref_vf)">
+<%
+src2 = vec_test_helpers.to_carr_str(src2)
+ref_vf = vec_test_helpers.to_carr_str(ref_vf)
+%>\
+namespace softrvv_${template_helper.op_code}_vf_test {
+namespace {
+${insert_variable_init(template_helper, src2, rs1, ref_vf)}
+
+class SoftRvv${template_helper.op_code.capitalize()}Test : public ::testing::Test {
+ protected:
+ void SetUp() override { memset(dest, 0, sizeof(dest)); }
+};
+${insert_test(template_helper)}\
+} // namespace
+} // namespace softrvv_${op}_vf_test\
+</%def>\
+
+<%def name="insert_variable_init(template_helper, src2, rs1, ref_vf)">
+<%
+ var_types = template_helper.get_var_types()
+%>\
+${var_types.src2_type} src2[] = {${src2}};
+${var_types.imm_type} rs1 = ${rs1};
+const int kAVL = sizeof(src2)/sizeof(src2[0]);
+${var_types.dest_type} dest[kAVL];
+
+${var_types.dest_type} ref_vf[kAVL] = {${ref_vf}};
+</%def>\
+
+<%def name="insert_test(template_helper)">
+<%
+var_types = template_helper.get_var_types()
+datatypes = template_helper.get_softrvv_template_data_type()
+%>\
+
+TEST_F(SoftRvv${template_helper.op_code.capitalize()}Test, VF) {
+ softrvv::${template_helper.op_code}_vf<${datatypes}>(dest, src2, &rs1, kAVL);\
+${insert_check(template_helper, var_types.dest_type, "ref_vf")}\
+}
+</%def>\
+
+<%def name="insert_check(template_helper, dest_type, ref_var)">
+% if template_helper.is_destination_mask_register():
+ assert_vec_mask_eq<${dest_type}>(kAVL, dest, ${ref_var});
+% else:
+ assert_vec_elem_eq<${dest_type}>(kAVL, dest, ${ref_var});
+% endif
+</%def>\
diff --git a/softrvv/tests/templates/opivv_test.tpl.cpp b/softrvv/tests/templates/opivv_test.tpl.cpp
new file mode 100644
index 0000000..08bd2e7
--- /dev/null
+++ b/softrvv/tests/templates/opivv_test.tpl.cpp
@@ -0,0 +1,53 @@
+<%!
+import vec_test_helpers
+%>\
+<%def name="test_opivv(template_helper, src2, src1, ref_vv)">
+<%
+src1 = vec_test_helpers.to_carr_str(src1)
+src2 = vec_test_helpers.to_carr_str(src2)
+ref_vv = vec_test_helpers.to_carr_str(ref_vv)
+%>\
+namespace softrvv_${template_helper.op_code}_vv_test {
+namespace {
+${insert_variable_init(template_helper, src2, src1, ref_vv)}
+
+class SoftRvv${template_helper.op_code.capitalize()}Test : public ::testing::Test {
+ protected:
+ void SetUp() override { memset(dest, 0, sizeof(dest)); }
+};
+${insert_test(template_helper)}\
+} // namespace
+} // namespace softrvv_${op}_vv_test\
+</%def>\
+
+<%def name="insert_variable_init(template_helper, src2, src1, ref_vv)">
+<%
+ var_types = template_helper.get_var_types()
+%>\
+${var_types.src1_type} src1[] = {${src1}};
+${var_types.src2_type} src2[] = {${src2}};
+const int kAVL = sizeof(src1)/sizeof(src1[0]);
+${var_types.dest_type} dest[kAVL];
+
+${var_types.dest_type} ref_vv[kAVL] = {${ref_vv}};
+</%def>\
+
+<%def name="insert_test(template_helper)">
+<%
+var_types = template_helper.get_var_types()
+datatypes = template_helper.get_softrvv_template_data_type()
+%>\
+TEST_F(SoftRvv${template_helper.op_code.capitalize()}Test, VV) {
+ softrvv::${template_helper.op_code}_vv<${datatypes}>(dest, src2, src1, kAVL);\
+${insert_check(template_helper, var_types.dest_type, "ref_vv")}\
+}
+
+</%def>\
+
+<%def name="insert_check(template_helper, dest_type, ref_var)">
+% if template_helper.is_destination_mask_register():
+ assert_vec_mask_eq<${dest_type}>(kAVL, dest, ${ref_var});
+% else:
+ assert_vec_elem_eq<${dest_type}>(kAVL, dest, ${ref_var});
+% endif
+</%def>\
diff --git a/softrvv/tests/templates/softrvv_vfadd_test.tpl.cpp b/softrvv/tests/templates/softrvv_vfadd_test.tpl.cpp
new file mode 100644
index 0000000..ec8695b
--- /dev/null
+++ b/softrvv/tests/templates/softrvv_vfadd_test.tpl.cpp
@@ -0,0 +1,14 @@
+<%inherit file="base.tpl.cpp"/>\
+<%namespace name="tests_vv" file="opivv_test.tpl.cpp"/>\
+<%namespace name="tests_vf" file="opivf_test.tpl.cpp"/>\
+<%
+import numpy as np
+import vec_test_helpers
+template_helper = vec_test_helpers.VecTemplateHelper(op, 32)
+src2, src1, rs1 = template_helper.get_test_inputs(n=5)
+ref_vv = src2 + src1
+ref_vf = src2 + rs1
+%>\
+${tests_vv.test_opivv(template_helper, src2, src1, ref_vv)}
+${tests_vf.test_opivf(template_helper, src2, rs1, ref_vf)}
+
diff --git a/softrvv/tests/templates/softrvv_vfsub_test.tpl.cpp b/softrvv/tests/templates/softrvv_vfsub_test.tpl.cpp
new file mode 100644
index 0000000..f27fd3a
--- /dev/null
+++ b/softrvv/tests/templates/softrvv_vfsub_test.tpl.cpp
@@ -0,0 +1,13 @@
+<%inherit file="base.tpl.cpp"/>\
+<%namespace name="tests_vv" file="opivv_test.tpl.cpp"/>
+<%namespace name="tests_vf" file="opivf_test.tpl.cpp"/>
+<%
+import numpy as np
+import vec_test_helpers
+template_helper = vec_test_helpers.VecTemplateHelper(op, 32)
+src2, src1, rs1 = template_helper.get_test_inputs(n=5)
+ref_vv = src2 - src1
+ref_vf = src2 - rs1
+%>\
+${tests_vv.test_opivv(template_helper, src2, src1, ref_vv)}
+${tests_vf.test_opivf(template_helper, src2, rs1, ref_vf)}
diff --git a/test_v_helpers/include/test_v_helpers.h b/test_v_helpers/include/test_v_helpers.h
index ba28e43..66760c0 100644
--- a/test_v_helpers/include/test_v_helpers.h
+++ b/test_v_helpers/include/test_v_helpers.h
@@ -8,6 +8,20 @@
#include "pw_unit_test/framework.h"
+#ifdef __cplusplus
+
+using float32_t = float;
+using float64_t = double;
+using float128_t = long double;
+
+#else
+
+typedef float float32_t;
+typedef double float64_t;
+typedef long double float128_t;
+
+#endif // __cplusplus
+
namespace test_v_helpers {
const int LMUL_MAX = 8;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 2230dd1..e2f55ff 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,3 +1,12 @@
+# vec_cc_generated_test(
+# NAME
+# vfadd
+# TEMPLATE
+# opivv_test.tpl.cpp
+# LINKOPTS
+# -Xlinker --defsym=__itcm_length__=128K
+# )
+
vec_cc_generated_test(
NAME
vsub
@@ -391,3 +400,12 @@
LINKOPTS
-Xlinker --defsym=__itcm_length__=128K
)
+
+vec_cc_test(
+ NAME
+ vfadd_test
+ SRCS
+ vector_vfadd_test.cpp
+ LINKOPTS
+ -Xlinker --defsym=__itcm_length__=128K
+)
\ No newline at end of file
diff --git a/tests/vector_vfadd_test.cpp b/tests/vector_vfadd_test.cpp
new file mode 100644
index 0000000..9ec1eac
--- /dev/null
+++ b/tests/vector_vfadd_test.cpp
@@ -0,0 +1,88 @@
+#include <limits.h>
+#include <riscv_vector.h>
+#include <softrvv.h>
+#include <springbok.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <stdint.h>
+#include <bit>
+#include <tuple>
+
+#include "pw_unit_test/framework.h"
+#include "test_v_helpers.h"
+
+#ifdef __cplusplus
+
+using float32_t = float;
+using float64_t = double;
+using float128_t = long double;
+
+#else
+
+typedef float float32_t;
+typedef double float64_t;
+typedef long double float128_t;
+
+#endif // __cplusplus
+
+namespace vfadd_vv_test
+{
+ namespace
+ {
+ using namespace test_v_helpers;
+
+ float src_vector_1[MAXVL_BYTES];
+ float src_vector_2[MAXVL_BYTES];
+ float dest_vector[MAXVL_BYTES];
+ float ref_dest_vector[MAXVL_BYTES];
+
+ class VfaddTest : public ::testing::Test {
+ protected:
+ void SetUp() override { zero_vector_registers(); }
+ void TearDown() override { zero_vector_registers(); }
+ };
+
+ TEST_F(VfaddTest, vfadd_vv32m1) {
+ for (int i = 0; i < AVL_COUNT; i++) {
+ int32_t avl = AVLS[i];
+ int vlmax;
+ int vl;
+
+ /* For non narrowing instructions all vectors have same type*/
+ std::tie(vlmax, vl) = vector_test_setup<int32_t>(
+ VLMUL::LMUL_M1, avl,
+ {dest_vector, ref_dest_vector, src_vector_1});
+
+ if (avl > vlmax) {
+ continue;
+ }
+
+ float *ptr_vec_1 = reinterpret_cast<float *>(src_vector_1);
+ float *ptr_vec_2 = reinterpret_cast<float *>(src_vector_2);
+ float *ptr_dest_vec = reinterpret_cast<float *>(dest_vector);
+ float *ptr_ref_dest_vec = reinterpret_cast<float *>(ref_dest_vector);
+
+ // set up values to test up to index of the AVL
+ fill_random_vector<float>(ptr_vec_1, avl);
+ fill_random_vector<float>(ptr_vec_2, avl);
+ memset(dest_vector, 0, MAXVL_BYTES);
+ memset(ref_dest_vector, 0, MAXVL_BYTES);
+
+ // Generate reference vector
+ softrvv::vfadd_vv<float>(ptr_ref_dest_vec, ptr_vec_2, ptr_vec_1, avl);
+ // Load vector registers
+ __asm__ volatile("vle32.v v8, (%0)" : : "r"(ptr_vec_1));
+ __asm__ volatile("vle32.v v16, (%0)" : : "r"(ptr_vec_2));
+
+ // Run target instruction
+ __asm__ volatile("vfadd.vv v24, v16, v8");
+
+ // Store result vector register
+ __asm__ volatile("vse32.v v24, (%0)" : : "r"(ptr_dest_vec));
+ // Check vector elements
+ assert_vec_elem_eq<float>(vlmax, dest_vector, ref_dest_vector);
+ }
+ }
+ }
+}