Skip to content

Commit c860cab

Browse files
committed
Merge branch 'google:main' into add_rvv_support
2 parents 27d8915 + 6f99459 commit c860cab

4 files changed

Lines changed: 79 additions & 103 deletions

File tree

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: riscv64-qemu-test
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
test:
7+
runs-on: ubuntu-latest
8+
env:
9+
RISCV_CROSSCOMPILE: "ON"
10+
riscv_gnu_toolchain_download_path: https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2025.07.03/riscv64-glibc-ubuntu-24.04-gcc-nightly-2025.07.03-nightly.tar.xz
11+
RISCV_PATH: /opt/riscv
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
with:
16+
submodules: recursive
17+
18+
- name: Install dependencies
19+
run: |
20+
sudo apt update
21+
sudo apt install -y --no-install-recommends \
22+
qemu-user qemu-user-static \
23+
build-essential \
24+
cmake \
25+
git
26+
sudo mkdir -p $RISCV_PATH
27+
wget ${riscv_gnu_toolchain_download_path} -O riscv-toolchain.tar.xz
28+
sudo tar -xvf riscv-toolchain.tar.xz -C $RISCV_PATH --strip-components=1
29+
sudo sed -i "s|libdir='/mnt/riscv/riscv64-unknown-linux-gnu/lib'|libdir='$RISCV_PATH/riscv64-unknown-linux-gnu/lib'|g" $RISCV_PATH/riscv64-unknown-linux-gnu/lib/libatomic.la
30+
31+
- name: Build and Run Unit Tests
32+
run: |
33+
export PATH=$RISCV_PATH/bin:$PATH
34+
export LD_LIBRARY_PATH="/opt/riscv/lib:$LD_LIBRARY_PATH"
35+
export QEMU_LD_PREFIX=$RISCV_PATH/sysroot
36+
mkdir build && cd build
37+
cmake -DCMAKE_BUILD_TYPE=Release ../
38+
make -j$(nproc)
39+
make test
40+
41+
- name: Run Benchmark
42+
run: ./build/snappy_benchmark
43+
working-directory: ./

snappy-internal.h

Lines changed: 13 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,21 @@
4949
#if SNAPPY_RVV_1 || SNAPPY_RVV_0_7
5050
#define SNAPPY_HAVE_RVV 1
5151
#include <riscv_vector.h>
52+
#else
53+
#define SNAPPY_HAVE_RVV 0
5254
#endif
5355

56+
#ifdef SNAPPY_RVV_1
57+
#define VSETVL_E8M2 __riscv_vsetvl_e8m2
58+
#define VLE8_V_U8M2 __riscv_vle8_v_u8m2
59+
#define VSE8_V_U8M2 __riscv_vse8_v_u8m2
60+
#elif SNAPPY_RVV_0_7
61+
#define VSETVL_E8M2 vsetvl_e8m2
62+
#define VLE8_V_U8M2 vle8_v_u8m2
63+
#define VSE8_V_U8M2 vse8_v_u8m2
64+
#endif
5465

55-
#if SNAPPY_HAVE_SSSE3 || SNAPPY_HAVE_NEON || SNAPPY_HAVE_RVV
66+
#if SNAPPY_HAVE_SSSE3 || SNAPPY_HAVE_NEON
5667
#define SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE 1
5768
#else
5869
#define SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE 0
@@ -66,23 +77,8 @@ namespace internal {
6677
using V128 = __m128i;
6778
#elif SNAPPY_HAVE_NEON
6879
using V128 = uint8x16_t;
69-
#elif SNAPPY_HAVE_RVV
70-
using V128 = vuint8m1_t;
71-
#endif
72-
73-
#ifdef SNAPPY_RVV_1
74-
#define VSETVL_E8M1 __riscv_vsetvl_e8m1
75-
#define VLE8_V_U8M1 __riscv_vle8_v_u8m1
76-
#define VSE8_V_U8M1 __riscv_vse8_v_u8m1
77-
#define VRGATHER_VV_U8M1 __riscv_vrgather_vv_u8m1
78-
#define VMV_V_X_U8M1 __riscv_vmv_v_x_u8m1
79-
#elif SNAPPY_RVV_0_7
80-
#define VSETVL_E8M1 vsetvl_e8m1
81-
#define VLE8_V_U8M1 vle8_v_u8m1
82-
#define VSE8_V_U8M1 vse8_v_u8m1
83-
#define VRGATHER_VV_U8M1 vrgather_vv_u8m1
84-
#define VMV_V_X_U8M1 vmv_v_x_u8m1
8580
#endif
81+
8682
// Load 128 bits of integer data. `src` must be 16-byte aligned.
8783
inline V128 V128_Load(const V128* src);
8884

@@ -132,31 +128,7 @@ inline V128 V128_Shuffle(V128 input, V128 shuffle_mask) {
132128

133129
inline V128 V128_DupChar(char c) { return vdupq_n_u8(c); }
134130

135-
#elif SNAPPY_HAVE_RVV
136-
inline V128 V128_Load(const V128* src) {
137-
size_t vl = VSETVL_E8M1(16);
138-
return VLE8_V_U8M1(reinterpret_cast<const uint8_t*>(src), vl);
139-
}
140-
141-
inline V128 V128_LoadU(const V128* src) {
142-
size_t vl = VSETVL_E8M1(16);
143-
return VLE8_V_U8M1(reinterpret_cast<const uint8_t*>(src), vl);
144-
}
145-
146-
inline void V128_StoreU(V128* dst, V128 val) {
147-
size_t vl = VSETVL_E8M1(16);
148-
VSE8_V_U8M1(reinterpret_cast<uint8_t*>(dst), val, vl);
149-
}
150-
151-
inline V128 V128_Shuffle(V128 input, V128 shuffle_mask) {
152-
size_t vl = VSETVL_E8M1(16);
153-
return VRGATHER_VV_U8M1(input, shuffle_mask, vl);
154-
}
155131

156-
inline V128 V128_DupChar(char c) {
157-
size_t vl = VSETVL_E8M1(16);
158-
return VMV_V_X_U8M1(static_cast<uint8_t>(c), vl);
159-
}
160132
#endif
161133
#endif // SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE
162134

snappy.cc

Lines changed: 22 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -282,18 +282,6 @@ inline char* IncrementalCopySlow(const char* src, char* op,
282282
// calling MakePatternMaskBytes(0, 6, index_sequence<16>()) and
283283
// MakePatternMaskBytes(16, 6, index_sequence<16>()) respectively.
284284

285-
// Selects the appropriate vector size based on the current architecture
286-
// vuint8m1_t, RISC-V vector type with fixed 128-bit size
287-
// (sizeof not used due to variable-length vector register in RVV)
288-
#if defined(__SSE2__) || defined(SNAPPY_HAVE_SSSE3)
289-
constexpr size_t kVectorSize = sizeof(V128); // __m128i
290-
#elif defined(__ARM_NEON) || defined(SNAPPY_HAVE_NEON)
291-
constexpr size_t kVectorSize = sizeof(uint8x16_t); // uint8x16_t
292-
#elif defined(SNAPPY_HAVE_RVV) || defined(__riscv_vector)
293-
constexpr size_t kVectorSize = 16; // vuint8m1_t
294-
#else
295-
#error "Unsupported architecture. Please define __SSE2__, __ARM_NEON, or SNAPPY_HAVE_RVV/__riscv_vector."
296-
#endif
297285

298286
template <size_t... indexes>
299287
inline constexpr std::array<char, sizeof...(indexes)> MakePatternMaskBytes(
@@ -342,20 +330,14 @@ static inline V128 LoadPattern(const char* src, const size_t pattern_size) {
342330
generation_mask);
343331
}
344332
// vuint8m1_t cannot be used as an element of std::pair
345-
#if SNAPPY_HAVE_RVV
346-
#define LoadPatternAndReshuffleMask(src, pattern_size) \
347-
V128 pattern = LoadPattern(src, pattern_size);\
348-
V128 reshuffle_mask = V128_Load(reinterpret_cast<const V128*>(\
349-
pattern_reshuffle_masks[pattern_size - 1].data()));
350-
#else
351333

352334
// Suppress -Wignored-attributes warning for __m128i in x86 SSE2 environment
353335
// warning: ignoring attributes on template argument 'snappy::internal::V128' {aka '__vector(2) long long int'} [-Wignored-attributes]
354336
// This occurs because __m128i has vector attributes (e.g., __attribute__((vector_size(16)))) that are ignored in template parameters.
355337
#ifdef __SSE2__
356338
#pragma GCC diagnostic push
357339
#pragma GCC diagnostic ignored "-Wignored-attributes"
358-
#endif
340+
359341

360342
SNAPPY_ATTRIBUTE_ALWAYS_INLINE
361343
static inline std::pair<V128 /* pattern */, V128 /* reshuffle_mask */>
@@ -411,14 +393,10 @@ static inline bool Copy64BytesWithPatternExtension(char* dst, size_t offset) {
411393
return true;
412394
}
413395
default: {
414-
#if SNAPPY_HAVE_RVV
415-
LoadPatternAndReshuffleMask(dst - offset, offset)
416-
#else
417396
auto pattern_and_reshuffle_mask =
418397
LoadPatternAndReshuffleMask(dst - offset, offset);
419398
V128 pattern = pattern_and_reshuffle_mask.first;
420399
V128 reshuffle_mask = pattern_and_reshuffle_mask.second;
421-
#endif
422400
for (int i = 0; i < 4; i++) {
423401
V128_StoreU(reinterpret_cast<V128*>(dst + 16 * i), pattern);
424402
pattern = V128_Shuffle(pattern, reshuffle_mask);
@@ -526,14 +504,10 @@ inline char* IncrementalCopy(const char* src, char* op, char* const op_limit,
526504
// Typically, the op_limit is the gating factor so try to simplify the loop
527505
// based on that.
528506
if (SNAPPY_PREDICT_TRUE(op_limit <= buf_limit - 15)) {
529-
#if SNAPPY_HAVE_RVV
530-
LoadPatternAndReshuffleMask(src, pattern_size);
531-
#else
532507
auto pattern_and_reshuffle_mask =
533508
LoadPatternAndReshuffleMask(src, pattern_size);
534509
V128 pattern = pattern_and_reshuffle_mask.first;
535510
V128 reshuffle_mask = pattern_and_reshuffle_mask.second;
536-
#endif
537511
// There is at least one, and at most four 16-byte blocks. Writing four
538512
// conditionals instead of a loop allows FDO to layout the code with
539513
// respect to the actual probabilities of each length.
@@ -556,14 +530,10 @@ inline char* IncrementalCopy(const char* src, char* op, char* const op_limit,
556530
}
557531
char* const op_end = buf_limit - 15;
558532
if (SNAPPY_PREDICT_TRUE(op < op_end)) {
559-
#if SNAPPY_HAVE_RVV
560-
LoadPatternAndReshuffleMask(src, pattern_size);
561-
#else
562533
auto pattern_and_reshuffle_mask =
563534
LoadPatternAndReshuffleMask(src, pattern_size);
564535
V128 pattern = pattern_and_reshuffle_mask.first;
565536
V128 reshuffle_mask = pattern_and_reshuffle_mask.second;
566-
#endif
567537
// This code path is relatively cold however so we save code size
568538
// by avoiding unrolling and vectorizing.
569539
//
@@ -1288,36 +1258,27 @@ void MemCopy64(char* dst, const void* src, size_t size) {
12881258
data = _mm256_lddqu_si256(static_cast<const __m256i *>(src) + 1);
12891259
_mm256_storeu_si256(reinterpret_cast<__m256i *>(dst) + 1, data);
12901260
}
1291-
// RVV acceleration available on RISC-V when compiled with -march=rv64gcv
1292-
#elif defined(__riscv) & SNAPPY_HAVE_RVV
1293-
uint8_t* dst_u8 = (uint8_t*)dst;
1294-
const uint8_t* src_u8 = (const uint8_t*)src;
1295-
//overlap bwd copy
1296-
if (src_u8 < dst_u8 && dst_u8 < src_u8 + size) {
1297-
size_t offset = size;
1298-
while (offset > 0) {
1299-
size_t vl = VSETVL_E8M1(offset);
1300-
offset -= vl;
1301-
vuint8m1_t vec = VLE8_V_U8M1(src_u8 + offset, vl);
1302-
VSE8_V_U8M1(dst_u8 + offset, vec, vl);
1303-
}
1304-
} else {
1305-
size_t vl = VSETVL_E8M1(size);
1306-
// if size >vl,use the max_vlen copy
1307-
if (vl < size) {
1308-
size_t offset = 0;
1309-
while (offset < size) {
1310-
vl = VSETVL_E8M1(size - offset);
1311-
vuint8m1_t vec = VLE8_V_U8M1(src_u8 + offset, vl);
1312-
VSE8_V_U8M1(dst_u8 + offset, vec, vl);
1313-
offset += vl;
1314-
}
1315-
} else {
1316-
// Copy the rest
1317-
vuint8m1_t vec = VLE8_V_U8M1(src_u8, vl);
1318-
VSE8_V_U8M1(dst_u8, vec, vl);
1319-
}
1320-
}
1261+
// RVV acceleration available on RISC-V when compiled with -march=rv64gcv
1262+
#elif defined(__riscv) && SNAPPY_HAVE_RVV
1263+
// Cast pointers to the type we will operate on.
1264+
unsigned char* dst_ptr = (unsigned char*)dst;
1265+
const unsigned char* src_ptr = (const unsigned char*)src;
1266+
size_t remaining_bytes = size;
1267+
//Loop as long as there are bytes remaining to be copied.
1268+
while (remaining_bytes > 0) {
1269+
//Set vector configuration: e8 (8-bit elements), m2 (LMUL=2).
1270+
//Use e8m2 configuration to maximize throughput.
1271+
size_t vl = VSETVL_E8M2(remaining_bytes);
1272+
//Load data from the current source pointer.
1273+
vuint8m2_t vec = VLE8_V_U8M2(src_ptr, vl);
1274+
//Store data to the current destination pointer.
1275+
VSE8_V_U8M2(dst_ptr, vec, vl);
1276+
//Update pointers and the remaining count.
1277+
src_ptr += vl;
1278+
dst_ptr += vl;
1279+
remaining_bytes -= vl;
1280+
}
1281+
13211282
#else
13221283
std::memmove(dst, src, kShortMemCopy);
13231284
//Profiling shows that nearly all copies are short.

third_party/benchmark

Submodule benchmark updated 166 files

0 commit comments

Comments
 (0)