This patch uses RISC-V vector instructions and zicbop prefetching to<br />optimize memory copies for 129~1600 byte ranges.<br /> <br />Signed-off-by: Qiguo Chen <chen.qiguo@zte.com.cn> <br />---<br /> .mailmap                           |   1 +<br /> config/riscv/meson.build           |  14 ++<br /> lib/eal/riscv/include/rte_memcpy.h | 303 ++++++++++++++++++++++++++++-<br /> 3 files changed, 316 insertions(+), 2 deletions(-)<br /> <br />diff --git a/.mailmap b/.mailmap<br />index e4d0590451..8fcdc518f9 100644<br />--- a/.mailmap<br />+++ b/.mailmap<br />@@ -1291,6 +1291,7 @@ Qi Zhang <qi.z.zhang@intel.com> <br /> Qian Hao <qi_an_hao@126.com> <br /> Qian Xu <qian.q.xu@intel.com> <br /> Qiao Liu <qiao.liu@intel.com> <br />+Qiguo Chen <chen.qiguo@zte.com.cn> <br /> Qimai Xiao <qimaix.xiao@intel.com> <br /> Qiming Chen <chenqiming_huawei@163.com> <br /> Qiming Yang <qiming.yang@intel.com> <br />diff --git a/config/riscv/meson.build b/config/riscv/meson.build<br />index f3daea0c0e..abba474b5e 100644<br />--- a/config/riscv/meson.build<br />+++ b/config/riscv/meson.build<br />@@ -146,6 +146,20 @@ if (riscv_extension_macros and<br />     endif<br /> endif<br />  <br />+# detect extensions<br />+# Requires intrinsics available in GCC 14.1.0+ and Clang 18.1.0+<br />+if (riscv_extension_macros and<br />+    (cc.get_define('__riscv_zicbop', args: machine_args) != ''))<br />+  if ((cc.get_id() == 'gcc' and cc.version().version_compare('>=14.1.0'))<br />+      or (cc.get_id() == 'clang' and cc.version().version_compare('>=18.1.0')))<br />+      message('Compiling with the zicbop extension')<br />+      machine_args += ['-DRTE_RISCV_FEATURE_PREFETCH']<br />+  else<br />+    warning('Detected zicbop extension but cannot use because intrinsics are not available (present in GCC 14.1.0+ and Clang 18.1.0+)')<br />+  endif<br />+endif<br />+<br />+<br /> # apply flags<br /> foreach flag: dpdk_flags<br />     if flag.length() > 0<br />diff --git a/lib/eal/riscv/include/rte_memcpy.h b/lib/eal/riscv/include/rte_memcpy.h<br />index d8a942c5d2..1be3ad748a 100644<br />--- a/lib/eal/riscv/include/rte_memcpy.h<br />+++ b/lib/eal/riscv/include/rte_memcpy.h<br />@@ -11,13 +11,291 @@<br /> #include <string.h> <br />  <br /> #include "rte_common.h" <br />+#include <rte_branch_prediction.h> <br />  <br /> #include "generic/rte_memcpy.h" <br />  <br />+#if defined(RTE_RISCV_FEATURE_V) && !(defined(RTE_RISCV_FEATURE_PREFETCH))<br />+#undef RTE_RISCV_FEATURE_V<br />+#endif<br />+<br />+#if defined(RTE_RISCV_FEATURE_V)<br />+#include "rte_cpuflags.h" <br />+#endif<br />+<br /> #ifdef __cplusplus<br /> extern "C" {<br /> #endif<br />  <br />+#if defined(RTE_RISCV_FEATURE_V)<br />+<br />+#define RISCV_VLENB         16<br />+#define MEMCPY_GLIBC        (1U << 0)<br />+#define MEMCPY_RISCV        (1U << 1)<br />+#define ALIGNMENT_MASK_128  0x7F<br />+#define ALIGNMENT_MASK_64   0x3F<br />+<br />+static uint8_t memcpy_alg = MEMCPY_GLIBC;<br />+<br />+<br />+static __rte_always_inline void<br />+memcpy_prefetch64_1(const uint8_t *src, uint8_t *dst)<br />+{<br />+    __asm__ (<br />+        "prefetch.r 64(%0)\n" <br />+        "prefetch.w 64(%1)" <br />+        :: "r"(src), "r"(dst)<br />+    );<br />+}<br />+<br />+static __rte_always_inline void<br />+memcpy_prefetch128_1(const uint8_t *src, uint8_t *dst)<br />+{<br />+    __asm__ (<br />+        "prefetch.r 128(%0)\n" <br />+        "prefetch.w 128(%1)" <br />+        :: "r"(src), "r"(dst)<br />+    );<br />+}<br />+<br />+static __rte_always_inline void<br />+memcpy_prefetch128_2(const uint8_t *src, uint8_t *dst)<br />+{<br />+    __asm__ (<br />+        "prefetch.r 128(%0);" <br />+        "prefetch.w 128(%1);" <br />+        "prefetch.r 192(%0);" <br />+        "prefetch.w 192(%1)" <br />+        :: "r"(src), "r"(dst)<br />+    );<br />+}<br />+<br />+<br />+static __rte_always_inline void<br />+_rte_mov32(uint8_t *dst, const uint8_t *src)<br />+{<br />+    uint32_t n = 32;<br />+    asm volatile (<br />+         "vsetvli t1, %2, e8, m2, ta, ma\n" <br />+         "vle8.v v2, (%1)\n" <br />+         "vse8.v v2, (%0)" <br />+         :: "r"(dst), "r"(src), "r"(n)<br />+         : "v2", "v3", "t1", "memory" <br />+     );<br />+}<br />+<br />+static __rte_always_inline void<br />+_rte_mov64(uint8_t *dst, const uint8_t *src)<br />+{<br />+    uint32_t n = 64;<br />+    asm volatile (<br />+        "vsetvli t3, %2, e8, m4, ta, ma\n" <br />+        "vle8.v v8, (%1)\n" <br />+        "vse8.v v8, (%0)" <br />+        :: "r"(dst), "r"(src), "r"(n)<br />+        :  "v8", "v9", "v10", "v11", "t3", "memory" <br />+     );<br />+}<br />+<br />+static __rte_always_inline void<br />+_rte_mov128(uint8_t *dst, const uint8_t *src)<br />+{<br />+    uint32_t n = 128;<br />+    asm volatile (<br />+        "vsetvli t4, %2, e8, m8, ta, ma\n" <br />+        "vle8.v v16, (%1)\n" <br />+        "vse8.v v16, (%0)" <br />+        :: "r"(dst), "r"(src), "r"(n)<br />+        : "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "t4", "memory" <br />+     );<br />+}<br />+<br />+static __rte_always_inline void<br />+_rte_mov256(uint8_t *dst, const uint8_t *src)<br />+{<br />+    memcpy_prefetch128_2(src, dst);<br />+    _rte_mov128(dst, src);<br />+    _rte_mov128(dst + 128, src + 128);<br />+}<br />+<br />+static __rte_always_inline void<br />+_rte_mov128blocks(uint8_t *dst, const uint8_t *src, size_t n)<br />+{<br />+    asm volatile (<br />+        "prefetch.r 64(%1)\n" <br />+        "prefetch.w 64(%0)\n" <br />+        "prefetch.r 128(%1)\n" <br />+        "prefetch.w 128(%0)\n" <br />+        "prefetch.r 192(%1)\n" <br />+        "prefetch.w 192(%0)\n" <br />+        "prefetch.r 256(%1)\n" <br />+        "prefetch.w 256(%0)\n" <br />+        "prefetch.r 320(%1)\n" <br />+        "prefetch.w 320(%0)\n" <br />+        "prefetch.r 384(%1)\n" <br />+        "prefetch.w 384(%0)\n" <br />+        "prefetch.r 448(%1)\n" <br />+        "prefetch.w 448(%0)\n" <br />+        "prefetch.r 512(%1)\n" <br />+        "li t6, 512\n" <br />+        "3:\n" <br />+        "li t5, 128;" <br />+        "vsetvli zero, t5, e8, m8, ta, ma\n" <br />+        "1:;" <br />+        "bgt %2, t6, 4f\n" <br />+        "j 2f\n" <br />+        "4:\n" <br />+        "prefetch.r 576(%1)\n" <br />+        "prefetch.r 640(%1)\n" <br />+        "2:\n" <br />+        "vle8.v   v16, (%1)\n" <br />+        "add      %1, %1, t5\n" <br />+        "vse8.v   v16, (%0)\n" <br />+        "add      %0, %0, t5\n" <br />+        "sub      %2, %2, t5\n" <br />+        "bnez     %2, 1b" <br />+        : "+r"(dst), "+r"(src), "+r"(n)<br />+        :<br />+        : "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "t5", "t6", "memory" <br />+    );<br />+}<br />+<br />+static __rte_always_inline void<br />+_rte_mov(uint8_t *dst, const uint8_t *src, uint32_t n)<br />+{<br />+    asm volatile (<br />+        "1:\n" <br />+        "vsetvli t4, %2, e8, m8, ta, ma\n" <br />+        "vle8.v v16, (%1)\n" <br />+        "add %1, %1, t4\n" <br />+        "vse8.v v16, (%0)\n" <br />+        "add %0, %0, t4\n" <br />+        "sub %2, %2, t4\n" <br />+        "bnez %2, 1b" <br />+        : "+r"(dst), "+r"(src), "+r"(n)<br />+        :<br />+        : "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "t4", "memory" <br />+     );<br />+}<br />+<br />+static __rte_always_inline void<br />+_rte_mov_aligned(uint8_t *dst, const uint8_t *src, uint32_t n)<br />+{<br />+    asm volatile (<br />+        "prefetch.r 128(%1)\n" <br />+        "prefetch.r 192(%1)\n" <br />+        "prefetch.r 256(%1)\n" <br />+        "prefetch.r 320(%1)\n" <br />+        "prefetch.r 384(%1)\n" <br />+        "prefetch.r 448(%1)\n" <br />+        "prefetch.r 512(%1)\n" <br />+        "prefetch.r 576(%1)\n" <br />+        "li t6, 640\n" <br />+        "1:\n" <br />+        "vsetvli t4, %2, e8, m8, ta, ma\n" <br />+        "vle8.v v16, (%1)\n" <br />+        "add %1, %1, t4\n" <br />+        "vse8.v v16, (%0)\n" <br />+        "add %0, %0, t4\n" <br />+        "sub %2, %2, t4\n" <br />+        "blt %2, t6, 3f\n" <br />+        "prefetch.r 512(%1)\n" <br />+        "prefetch.r 576(%1)\n" <br />+        "3:\n" <br />+        "bnez %2, 1b" <br />+        : "+r"(dst), "+r"(src), "+r"(n)<br />+        :<br />+        : "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "t4", "t6", "memory" <br />+     );<br />+}<br />+<br />+static __rte_always_inline void *<br />+_rte_memcpy(uint8_t *dst, const uint8_t *src, size_t n)<br />+{<br />+    void *ret = dst;<br />+    size_t dstofss;<br />+    uint32_t bn;<br />+<br />+    if (n <= 384) {<br />+        if (n >= 256) {<br />+            memcpy_prefetch128_2(src, dst);<br />+            n -= 256;<br />+            _rte_mov128(dst, src);<br />+            _rte_mov128((uint8_t *)dst + 128, (const uint8_t *)src + 128);<br />+            src = (const uint8_t *)src + 256;<br />+            dst = (uint8_t *)dst + 256;<br />+        }<br />+        if (n >= 128) {<br />+            memcpy_prefetch128_1(src, dst);<br />+            n -= 128;<br />+            _rte_mov128(dst, src);<br />+            src = (const uint8_t *)src + 128;<br />+            dst = (uint8_t *)dst + 128;<br />+        }<br />+<br />+        if (n >= 64) {<br />+            memcpy_prefetch64_1(src, dst);<br />+            n -= 64;<br />+            _rte_mov64(dst, src);<br />+            src = (const uint8_t *)src + 64;<br />+            dst = (uint8_t *)dst + 64;<br />+        }<br />+<br />+        if (n > 32) {<br />+            _rte_mov32(dst, src);<br />+            _rte_mov32((uint8_t *)dst - 32 + n,<br />+                    (const uint8_t *)src - 32 + n);<br />+            return ret;<br />+        }<br />+<br />+        if (n > 0) {<br />+            _rte_mov32((uint8_t *)dst - 32 + n,<br />+                    (const uint8_t *)src - 32 + n);<br />+        }<br />+        return ret;<br />+    }<br />+<br />+    /**<br />+     * Make store aligned when copy size exceeds 256 bytes.<br />+     */<br />+    dstofss = (uintptr_t)dst & ALIGNMENT_MASK_64;<br />+    if (dstofss > 0) {<br />+        dstofss = 64 - dstofss;<br />+        n -= dstofss;<br />+        _rte_mov64(dst, src);<br />+        src = (const uint8_t *)src + dstofss;<br />+        dst = (uint8_t *)dst + dstofss;<br />+    }<br />+<br />+    /**<br />+     * Copy 128-byte blocks<br />+     */<br />+    if ((uintptr_t)src & ALIGNMENT_MASK_64)    {<br />+        bn = n - (n & ALIGNMENT_MASK_128);<br />+        _rte_mov128blocks(dst, src, bn);<br />+        n = n & ALIGNMENT_MASK_128;<br />+        src = (const uint8_t *)src + bn;<br />+        dst = (uint8_t *)dst + bn;<br />+        _rte_mov(dst, src, n);<br />+    } else<br />+        _rte_mov_aligned(dst, src, n);<br />+<br />+    return ret;<br />+}<br />+<br />+#endif<br />+<br />+/*----------------------api---------------------------------------------------*/<br />+static __rte_always_inline void *<br />+rte_memcpy(void *dst, const void *src, size_t n)<br />+{<br />+#if defined(RTE_RISCV_FEATURE_V)<br />+    if (likely((memcpy_alg == MEMCPY_RISCV) && (n >= 128) && (n < 2048)))<br />+        return _rte_memcpy((uint8_t *)dst, (const uint8_t *)src, n);<br />+#endif<br />+    return memcpy(dst, src, n);<br />+}<br />+<br /> static inline void<br /> rte_mov16(uint8_t *dst, const uint8_t *src)<br /> {<br />@@ -51,10 +329,31 @@ rte_mov128(uint8_t *dst, const uint8_t *src)<br /> static inline void<br /> rte_mov256(uint8_t *dst, const uint8_t *src)<br /> {<br />-    memcpy(dst, src, 256);<br />+#if defined(RTE_RISCV_FEATURE_V)<br />+    if (likely(memcpy_alg == MEMCPY_RISCV))<br />+        _rte_mov256(dst, src);<br />+    else<br />+#endif<br />+        memcpy(dst, src, 256);<br />+}<br />+/*----------------------------------------------------------------------------*/<br />+#if defined(RTE_RISCV_FEATURE_V)<br />+static inline long<br />+riscv_vlenb(void)<br />+{<br />+    long vlenb;<br />+    asm ("csrr %0, 0xc22" : "=r"(vlenb));<br />+    return vlenb;<br /> }<br />  <br />-#define rte_memcpy(d, s, n)    memcpy((d), (s), (n))<br />+RTE_INIT(rte_vect_memcpy_init)<br />+{<br />+    long vlenb = riscv_vlenb();<br />+    if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_RISCV_ISA_V) && (vlenb >= RISCV_VLENB))<br />+        memcpy_alg = MEMCPY_RISCV;<br />+}<br />+#endif<br />+<br />  <br /> #ifdef __cplusplus<br /> }<br />--  <br />2.21.0.windows.1<br />