<span style="font-family:SimSun;">> riscv support rte_memcpy in vector</span><br>
<span style="font-family:SimSun;">> This patch implements RISC-V vector intrinsics</span><br>
<span style="font-family:SimSun;"><br>
</span><br>
<span style="font-family:SimSun;">Please adjust the title and msg to mention that zicbop has been introduced, and that intrinsic is not currently being used</span><br>
<span style="font-family:SimSun;"><br>
</span><br>
<span style="font-family:SimSun;">config/riscv/meson.build</span><br>
<span style="font-family:SimSun;"><br>
</span><br>
<span style="font-family:SimSun;">> # detect extensions</span><br>
<span style="font-family:SimSun;">> # Requires intrinsics available in GCC 14.1.0+ and Clang 18.1.0+</span><br>
<span style="font-family:SimSun;">> if (riscv_extension_macros and</span><br>
<span style="font-family:SimSun;">>     (cc.get_define('__riscv_zicbop', args: machine_args) != ''))</span><br>
<span style="font-family:SimSun;">>   if ((cc.get_id() == 'gcc' and cc.version().version_compare('>=14.1.0'))</span><br>
<span style="font-family:SimSun;">>       or (cc.get_id() == 'clang' and cc.version().version_compare('>=18.1.0')))</span><br>
<span style="font-family:SimSun;">>       message('Compiling with the zicbop extension')</span><br>
<span style="font-family:SimSun;">>       machine_args += ['-DRTE_RISCV_FEATURE_PREFETCH']</span><br>
<span style="font-family:SimSun;">>   else</span><br>
<span style="font-family:SimSun;">>     warning('Detected zicbop extension but cannot use because intrinsics are not available (present in GCC 14.1.0+ and Clang 18.1.0+)')</span><br>
<span style="font-family:SimSun;">>   endif</span><br>
<span style="font-family:SimSun;">> endif</span><br>
<span style="font-family:SimSun;"><br>
</span><br>
<span style="font-family:SimSun;">The implementation does not involve intrinsics</span><br>
<span style="font-family:SimSun;"><br>
</span><br>
<span style="font-family:SimSun;">>     16  0 -  0( 57.49%)   1 -  1(  7.30%)   2 -  2(  0.19%)   3 -  3(  3.19%) </span><br>
<span style="font-family:SimSun;">>     17  0 -  0( 53.78%)   3 -  2( 51.65%)   4 -  3( 37.35%)   4 -  3( 23.94%) </span><br>
<span style="font-family:SimSun;">>     31  0 -  0( 27.02%)   3 -  2( 51.99%)   4 -  3( 37.34%)   4 -  3( 24.09%) </span><br>
<span style="font-family:SimSun;">>     32  0 -  0( 56.82%)   3 -  2( 50.42%)   4 -  3( 39.73%)   4 -  3( 25.04%) </span><br>
<span style="font-family:SimSun;">>     33  0 -  0( 30.60%)   3 -  3( 30.94%)   6 -  4( 46.89%)   6 -  5( 26.21%) </span><br>
<span style="font-family:SimSun;">>     63  0 -  0( 16.84%)   4 -  3( 21.57%)   6 -  5( 31.74%)   7 -  6( 18.01%) </span><br>
<span style="font-family:SimSun;">>     64  0 -  0( 21.98%)   4 -  3( 21.35%)   6 -  5( 36.13%)   7 -  6( 20.05%) </span><br>
<span style="font-family:SimSun;"><br>
</span><br>
<span style="font-family:SimSun;">It looks like there's a performance degradation in the 0-128 range, can you fix it?</span><br>
<span style="font-family:SimSun;"><br>
</span><br>
<span style="font-family:SimSun;">eal/riscv/include/rte_memcpy.h</span><br>
<span style="font-family:SimSun;"><br>
</span><br>
<span style="font-family:SimSun;">> #define ALIGNMENT_MASK_16    0xF</span><br>
<span style="font-family:SimSun;"><br>
</span><br>
<span style="font-family:SimSun;">unused</span><br>
<span style="font-family:SimSun;"><br>
</span><br>
<span style="font-family:SimSun;">>/*else*/</span><br>
<span style="font-family:SimSun;"><br>
</span><br>
<span style="font-family:SimSun;">Please remove /*else*/</span><br>
<span style="font-family:SimSun;"><br>
</span><br>
<span style="font-family:SimSun;">> static __rte_always_inline void *</span><br>
<span style="font-family:SimSun;">> _rte_memcpy(void *dst, const void *src, size_t n)</span><br>
<span style="font-family:SimSun;">> {</span><br>
<span style="font-family:SimSun;">>  return _rte_memcpy_generic((uint8_t *)dst, (const uint8_t *)src, n);</span><br>
<span style="font-family:SimSun;">> }</span><br>
<span style="font-family:SimSun;"><br>
</span><br>
<span style="font-family:SimSun;">No need for an extra function call; you can write the implementation directly in the function</span><br>
<div style="font-family:SimSun;white-space:nowrap;">
        <br>
</div>
<br>
<br>
<br>
<blockquote name="replyContent" class="ReferenceQuote" style="font-family:SimSun;padding-left:5px;margin-left:5px;border-left:2px solid #B6B6B6;margin-right:0px;">
        -----原始邮件-----<br>
<b>发件人:</b><span id="rc_from">"Qiguo Chen" <chen.qiguo@zte.com.cn></span><br>
<b>发送时间:</b><span id="rc_senttime">2025-10-16 17:09:33 (星期四)</span><br>
<b>收件人:</b> stanislaw.kardach@gmail.com, sunyuechi@iscas.ac.cn, stephen@networkplumber.org<br>
<b>抄送:</b> dev@dpdk.org, bruce.richardson@intel.com, "Qiguo Chen" <chen.qiguo@zte.com.cn><br>
<b>主题:</b> [PATCH v1 1/2] riscv support rte_memcpy in vector<br>
<br>
This patch implements RISC-V vector intrinsics<br>
to accelerate memory copy operations for byte range (129~1600).<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 | 310 ++++++++++++++++++++++++++++-<br>
 3 files changed, 323 insertions(+), 2 deletions(-)<br>
<br>
diff --git a/.mailmap b/.mailmap<br>
index 08e5ec8560..178c5f44f4 100644<br>
--- a/.mailmap<br>
+++ b/.mailmap<br>
@@ -1285,6 +1285,7 @@ Qian Hao <qi_an_hao@126.com> <br>
 Qian Xu <qian.q.xu@intel.com> <br>
 Qiao Liu <qiao.liu@intel.com> <br>
 Qi Fu <qi.fu@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(&apos;__riscv_zicbop&apos;, args: machine_args) != &apos;&apos;))<br>
+  if ((cc.get_id() == &apos;gcc&apos; and cc.version().version_compare(&apos;>=14.1.0&apos;))<br>
+      or (cc.get_id() == &apos;clang&apos; and cc.version().version_compare(&apos;>=18.1.0&apos;)))<br>
+      message(&apos;Compiling with the zicbop extension&apos;)<br>
+      machine_args += [&apos;-DRTE_RISCV_FEATURE_PREFETCH&apos;]<br>
+  else<br>
+    warning(&apos;Detected zicbop extension but cannot use because intrinsics are not available (present in GCC 14.1.0+ and Clang 18.1.0+)&apos;)<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..6f8cb0d4a4 100644<br>
--- a/lib/eal/riscv/include/rte_memcpy.h<br>
+++ b/lib/eal/riscv/include/rte_memcpy.h<br>
@@ -11,6 +11,7 @@<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>
@@ -18,6 +19,290 @@<br>
 extern "C" {<br>
 #endif<br>
  <br>
+<br>
+#if defined(RTE_RISCV_FEATURE_V) && !(defined(RTE_RISCV_FEATURE_PREFETCH))<br>
+#undef RTE_RISCV_FEATURE_V<br>
+#endif<br>
+<br>
+<br>
+#if defined(RTE_RISCV_FEATURE_V)<br>
+<br>
+#include "rte_cpuflags.h" <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>
+#define ALIGNMENT_MASK_16    0xF<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_generic(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>
+static __rte_always_inline void *<br>
+_rte_memcpy(void *dst, const void *src, size_t n)<br>
+{<br>
+    return _rte_memcpy_generic((uint8_t *)dst, (const uint8_t *)src, n);<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(dst, src, n);<br>
+    /*else*/<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 +336,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>
</blockquote>