Skip to content

optimize base64 for riscv64 with RVV vrgather and vectorized decode#3388

Merged
chenBright merged 2 commits into
apache:masterfrom
Felix-Gong:riscv-base64-rvv
Jul 16, 2026
Merged

optimize base64 for riscv64 with RVV vrgather and vectorized decode#3388
chenBright merged 2 commits into
apache:masterfrom
Felix-Gong:riscv-base64-rvv

Conversation

@Felix-Gong

@Felix-Gong Felix-Gong commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

RVV-accelerated base64 encode/decode for RISC-V 64-bit (rv64gcv).

Changes

  • modp_b64_rvv.cc: RVV vrgather encode + vectorized decode (80% RVV)
  • modp_b64_rvv.h: Apache-2.0 license header
  • modp_b64.cc: Runtime dispatch via USE_RVV_BASE64
  • BUILD.bazel: Add modp_b64_rvv.cc to BUTIL_SRCS

Encode

Scalar 6-bit index extraction + vectorized vrgather lookup (16 bytes/iter, LMUL=4).
Processes 12 input bytes → 16 output bytes per vector loop iteration.

Decode

Vectorized range classification (A-Z, a-z, 0-9, +, /) + vmerge chain.
Final 4×6→3 byte packing remains scalar (data dependencies prevent vectorization).

Performance (SG2044 rv64gcv, 10-round avg, -O2)

Operation Scalar RVV Speedup
Encode 490–525 MB/s 600–670 MB/s 1.20–1.35×
Decode 615–640 MB/s 720–780 MB/s 1.14–1.23×

Tested

  • RFC 4648 test vectors (7/7)
  • Random roundtrip (256/256)
  • brpc_base64_unittest all passed

- Add RVV-accelerated base64 encode using vrgather vector indexed
  load for parallel table lookup (16 bytes per iteration, LMUL=4)
- Add RVV-accelerated base64 decode using vectorized range comparisons
  and vmerge chain for classification (16 input bytes per iteration)
- Integrate RVV dispatch into modp_b64.cc with compile-time selection
  when __riscv_vector is defined
- Add modp_b64_rvv.cc to CMakeLists.txt build sources
- Performance (SG2044 rv64gcv): decode 3-5x faster, up to 764 MB/s
- Tested with RFC 4648 vectors and 100-round random data roundtrip

Signed-off-by: Xiaofei Gong <gongxiaofei24@iscas.ac.cn>
Signed-off-by: YuanSheng <yuansheng@isrc.iscas.ac.cn>
@Felix-Gong
Felix-Gong force-pushed the riscv-base64-rvv branch 2 times, most recently from 0b651dc to 0b98453 Compare July 15, 2026 00:25
@chenBright
chenBright requested a review from Copilot July 15, 2026 02:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces RISC-V Vector (RVV) accelerated base64 encode/decode paths in the existing modp_b64 implementation under src/butil/third_party/, aiming to improve performance on rv64gcv while keeping non-RVV builds unchanged via compile-time dispatch.

Changes:

  • Add RVV-specific base64 encode/decode implementation (modp_b64_rvv.{h,cc}) and dispatch to it from modp_b64.cc when __riscv_vector is available.
  • Include the RVV header from modp_b64.h for RVV builds.
  • Add the new RVV source file to the CMake build.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/butil/third_party/modp_b64/modp_b64.h Includes RVV header when building with RVV enabled.
src/butil/third_party/modp_b64/modp_b64.cc Adds compile-time RVV dispatch for encode/decode.
src/butil/third_party/modp_b64/modp_b64_rvv.h Declares RVV-accelerated encode/decode entry points.
src/butil/third_party/modp_b64/modp_b64_rvv.cc Implements RVV-accelerated encode/decode routines.
CMakeLists.txt Adds the RVV implementation file to BUTIL_SOURCES.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,23 @@
/* ... Apache 2.0 license header ... */

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Replaced the placeholder with the full Apache-2.0 license header matching the style used in other modp_b64 files.

break;
}

return (size_t)(d - (uint8_t*)dest);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Added *d = '\0' before return in both the RVV fast path and scalar tail, matching modp_b64_encode() behavior.

Comment on lines +150 to +154
if (len == 0) return 0;

size_t i = 0;
uint8_t* p = (uint8_t*)dest;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Added trailing '=' stripping loop before decode, matching modp_b64_decode() validation logic.

Comment on lines +215 to +237
/* Scalar fallback for remaining <16 bytes or chunks with errors */
{
size_t remaining = len - i;
const uint8_t* s = (const uint8_t*)(src + i);
uint8_t* d = p;

for (size_t si = 0; si + 4 <= remaining; si += 4) {
uint8_t c0 = s[si], c1 = s[si+1], c2 = s[si+2], c3 = s[si+3];
int d0, d1, d2, d3;

#define DECODE_CHAR(c, val) do { if (c >= 'A' && c <= 'Z') val = c - 'A'; else if (c >= 'a' && c <= 'z') val = c - 'a' + 26; else if (c >= '0' && c <= '9') val = c - '0' + 52; else if (c == '+') val = 62; else if (c == '/') val = 63; else return MODP_B64_RVV_ERROR; } while (0)

DECODE_CHAR(c0, d0); DECODE_CHAR(c1, d1);
DECODE_CHAR(c2, d2); DECODE_CHAR(c3, d3);

#undef DECODE_CHAR

*d++ = (uint8_t)((d0 << 2) | (d1 >> 4));
*d++ = (uint8_t)(((d1 & 0x0F) << 4) | (d2 >> 2));
*d++ = (uint8_t)(((d2 & 0x03) << 6) | d3);
}
return (size_t)(d - (uint8_t*)dest);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Added explicit handling for leftover 2 and 3 chars after the main decode loop, producing the correct partial output (1 or 2 bytes respectively).

Comment thread CMakeLists.txt
Comment on lines 419 to +420
${PROJECT_SOURCE_DIR}/src/butil/third_party/modp_b64/modp_b64.cc
${PROJECT_SOURCE_DIR}/src/butil/third_party/modp_b64/modp_b64_rvv.cc

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Added modp_b64_rvv.cc to the BUTIL_SRCS list in BUILD.bazel.

- Replace placeholder license in modp_b64_rvv.h with Apache-2.0 header
- Add NUL terminator in rvv_modp_b64_encode scalar tail
- Strip trailing '=' padding at entry of rvv_modp_b64_decode
- Handle leftover 2/3 chars in decode scalar fallback
- Add modp_b64_rvv.cc to BUILD.bazel BUTIL_SRCS

All 5 fixes verified on real rv64gcv hardware (8/8 gtest pass).

Signed-off-by: Xiaofei Gong <gongxiaofei24@iscas.ac.cn>
Signed-off-by: YuanSheng <yuansheng@isrc.iscas.ac.cn>
@wwbmmm

wwbmmm commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

LGTM

@chenBright chenBright left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@chenBright
chenBright merged commit 2f1a7e1 into apache:master Jul 16, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants