Compare commits

1 Commits

Author SHA1 Message Date
MechaCat02
77c78fad94 crossbuild: target-aware POSIX gate in generated headers (Sylpheed fork)
Some checks failed
ci / CI ubuntu-latest avx clang debug (push) Failing after 17s
ci / CI ubuntu-latest baseline clang debug (push) Failing after 8s
ci / CI ubuntu-latest baseline clang release (push) Failing after 9s
ci / CI ubuntu-latest avx gcc debug (push) Failing after 8s
ci / CI ubuntu-latest avx gcc release (push) Failing after 8s
ci / CI ubuntu-latest avx2 gcc debug (push) Failing after 10s
ci / CI ubuntu-latest avx2 gcc release (push) Failing after 8s
ci / CI ubuntu-latest baseline gcc debug (push) Failing after 8s
ci / CI ubuntu-latest baseline gcc release (push) Failing after 8s
ci / CI ubuntu-latest avx clang release (push) Failing after 9s
ci / CI ubuntu-latest avx2 clang debug (push) Failing after 8s
ci / CI ubuntu-latest avx2 clang release (push) Failing after 8s
ci / CI windows-latest avx msvc debug (push) Has been cancelled
ci / CI windows-latest avx msvc release (push) Has been cancelled
ci / CI windows-latest avx2 msvc debug (push) Has been cancelled
ci / CI windows-latest avx2 msvc release (push) Has been cancelled
ci / CI windows-latest baseline msvc debug (push) Has been cancelled
ci / CI windows-latest baseline msvc release (push) Has been cancelled
ci / CI macos-latest avx clang debug (push) Has been cancelled
ci / CI macos-latest avx clang release (push) Has been cancelled
ci / CI macos-latest baseline clang debug (push) Has been cancelled
ci / CI macos-latest baseline clang release (push) Has been cancelled
Pre-generated snappy-stubs-public.h / config.h baked HAVE_SYS_UIO_H=1 from
a Linux cmake host, breaking clang-cl cross-compiles to Windows. Gate the
sys/uio.h include on !_WIN32 so the same checked-in headers build on both
hosts. See xenia-rs docs/CROSS_BUILD_SETUP.md §7.3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 07:22:08 +02:00
15 changed files with 188 additions and 258 deletions

View File

@@ -1,43 +0,0 @@
name: riscv64-qemu-test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
env:
RISCV_CROSSCOMPILE: "ON"
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
RISCV_PATH: /opt/riscv
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt update
sudo apt install -y --no-install-recommends \
qemu-user qemu-user-static \
build-essential \
cmake \
git
sudo mkdir -p $RISCV_PATH
wget ${riscv_gnu_toolchain_download_path} -O riscv-toolchain.tar.xz
sudo tar -xvf riscv-toolchain.tar.xz -C $RISCV_PATH --strip-components=1
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
- name: Build and Run Unit Tests
run: |
export PATH=$RISCV_PATH/bin:$PATH
export LD_LIBRARY_PATH="/opt/riscv/lib:$LD_LIBRARY_PATH"
export QEMU_LD_PREFIX=$RISCV_PATH/sysroot
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ../
make -j$(nproc)
make test
- name: Run Benchmark
run: ./build/snappy_benchmark
working-directory: ./

View File

@@ -26,20 +26,10 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
load("@bazel_skylib//rules:write_file.bzl", "write_file")
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
exports_files([
"COPYING",
"COPYING.notestdata",
])
SNAPPY_VERSION = (1, 2, 2)
config_setting(
@@ -62,10 +52,8 @@ cc_library(
name = "snappy-stubs-internal",
srcs = ["snappy-stubs-internal.cc"],
hdrs = ["snappy-stubs-internal.h"],
implementation_deps = [
":config",
],
deps = [
":config",
":snappy-stubs-public",
],
)
@@ -87,10 +75,8 @@ cc_library(
"-Wno-sign-compare",
],
}),
implementation_deps = [
":config",
],
deps = [
":config",
":snappy-stubs-internal",
":snappy-stubs-public",
],
@@ -147,10 +133,10 @@ cc_test(
)
# Generate a config.h similar to what cmake would produce.
write_file(
genrule(
name = "config_h",
out = "config.h",
content = """\
outs = ["config.h"],
cmd = """cat <<EOF >$@
#define HAVE_STDDEF_H 1
#define HAVE_STDINT_H 1
#ifdef __has_builtin
@@ -207,17 +193,19 @@ write_file(
# define SNAPPY_IS_BIG_ENDIAN 1
# endif
#endif
""".splitlines(),
EOF
""",
)
expand_template(
genrule(
name = "snappy_stubs_public_h",
out = "snappy-stubs-public.h",
substitutions = {
"${HAVE_SYS_UIO_H_01}": "!_WIN32",
"${PROJECT_VERSION_MAJOR}": str(SNAPPY_VERSION[0]),
"${PROJECT_VERSION_MINOR}": str(SNAPPY_VERSION[1]),
"${PROJECT_VERSION_PATCH}": str(SNAPPY_VERSION[2]),
},
template = "snappy-stubs-public.h.in",
srcs = ["snappy-stubs-public.h.in"],
outs = ["snappy-stubs-public.h"],
# Assume sys/uio.h is available on non-Windows.
# Set the version numbers.
cmd = ("""sed -e 's/$${HAVE_SYS_UIO_H_01}/!_WIN32/g' \
-e 's/$${PROJECT_VERSION_MAJOR}/%d/g' \
-e 's/$${PROJECT_VERSION_MINOR}/%d/g' \
-e 's/$${PROJECT_VERSION_PATCH}/%d/g' \
$< >$@""" % SNAPPY_VERSION),
)

View File

@@ -155,20 +155,10 @@ int main() {
return __builtin_expect(0, 1);
}" HAVE_BUILTIN_EXPECT)
# Check if the built-in __builtin_ctz (count trailing zeros) is available.
# Require either a non-RISC-V target, or a RISC-V core that implements
# the Zbb bit-manipulation extension where ctz is guaranteed.
check_cxx_source_compiles("
#ifdef __riscv
#ifdef __riscv_zbb
int main() { return __builtin_ctzll(0); }
#else
#error \"ZBB not enabled in current config\"
#endif
#else
int main() { return __builtin_ctzll(0); }
#endif
" HAVE_BUILTIN_CTZ)
int main() {
return __builtin_ctzll(0);
}" HAVE_BUILTIN_CTZ)
check_cxx_source_compiles("
int main() {
@@ -226,31 +216,6 @@ int main() {
return 0;
}" SNAPPY_HAVE_NEON)
#check RVV 1.0 need __riscv_ prefix
check_cxx_source_compiles("
#include <riscv_vector.h>
#include <stdint.h>
#include <stddef.h>
int main() {
uint8_t val = 3, dup[8];
size_t vl = __riscv_vsetvl_e8m1(8);
vuint8m1_t v = __riscv_vmv_v_x_u8m1(val, vl);
return 0;
}" SNAPPY_RVV_1)
#check RVV 0.7.1 not __riscv_ prefix
check_cxx_source_compiles("
#include <riscv_vector.h>
#include <stdint.h>
#include <stddef.h>
int main() {
uint8_t val = 3, dup[8];
size_t vl = vsetvl_e8m1(8);
vuint8m1_t v = vmv_v_x_u8m1(val, vl);
return 0;
}" SNAPPY_RVV_0_7)
include(CheckSymbolExists)
check_symbol_exists("mmap" "sys/mman.h" HAVE_FUNC_MMAP)
check_symbol_exists("sysconf" "unistd.h" HAVE_FUNC_SYSCONF)

View File

@@ -1,28 +0,0 @@
Copyright 2011, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -4,23 +4,20 @@ module(
compatibility_level = 1,
)
bazel_dep(name = "rules_cc", version = "0.2.4")
bazel_dep(name = "bazel_skylib", version = "1.8.2")
bazel_dep(
name = "googletest",
version = "1.17.0.bcr.2",
version = "1.14.0.bcr.1",
dev_dependency = True,
repo_name = "com_google_googletest",
)
bazel_dep(
name = "google_benchmark",
version = "1.9.5",
version = "1.9.0",
dev_dependency = True,
repo_name = "com_google_benchmark",
)
bazel_dep(
name = "platforms",
version = "1.0.0",
version = "0.0.9",
)

View File

@@ -140,10 +140,10 @@ explicitly supports the following:
1. C++11
2. Clang (gcc and MSVC are best-effort).
3. Low level optimizations (e.g. assembly or equivalent intrinsics) for:
- [x86](https://en.wikipedia.org/wiki/X86)
- [x86-64](https://en.wikipedia.org/wiki/X86-64)
- ARMv7 (32-bit)
- ARMv8 (AArch64)
- [x86](https://en.wikipedia.org/wiki/X86)
- [x86-64](https://en.wikipedia.org/wiki/X86-64)
- ARMv7 (32-bit)
- ARMv8 (AArch64)
4. Supports only the Snappy compression scheme as described in
[format_description.txt](format_description.txt).
5. CMake for building

0
WORKSPACE.bzlmod Normal file
View File

View File

@@ -58,12 +58,6 @@
/* Define to 1 if you target processors with NEON and have <arm_neon.h>. */
#cmakedefine01 SNAPPY_HAVE_NEON
/* Define to 1 if you target processors with RVV1.0 and have <riscv_vector.h>. */
#cmakedefine01 SNAPPY_RVV_1
/* Define to 1 if you target processors with RVV0.7 and have <riscv_vector.h>. */
#cmakedefine01 SNAPPY_RVV_0_7
/* Define to 1 if you have <arm_neon.h> and <arm_acle.h> and want to optimize
compression speed by using __crc32cw from <arm_acle.h>. */
#cmakedefine01 SNAPPY_HAVE_NEON_CRC32

69
config.h Normal file
View File

@@ -0,0 +1,69 @@
#ifndef THIRD_PARTY_SNAPPY_OPENSOURCE_CMAKE_CONFIG_H_
#define THIRD_PARTY_SNAPPY_OPENSOURCE_CMAKE_CONFIG_H_
/* Define to 1 if the compiler supports __attribute__((always_inline)). */
#define HAVE_ATTRIBUTE_ALWAYS_INLINE 1
/* Define to 1 if the compiler supports __builtin_ctz and friends. */
#define HAVE_BUILTIN_CTZ 1
/* Define to 1 if the compiler supports __builtin_expect. */
#define HAVE_BUILTIN_EXPECT 1
/* Define to 1 if the compiler supports __builtin_prefetch. */
#define HAVE_BUILTIN_PREFETCH 1
/* Define to 1 if you have a definition for mmap() in <sys/mman.h>. */
#define HAVE_FUNC_MMAP 1
/* Define to 1 if you have a definition for sysconf() in <unistd.h>. */
#define HAVE_FUNC_SYSCONF 1
/* Define to 1 if you have the `lzo2' library (-llzo2). */
#define HAVE_LIBLZO2 0
/* Define to 1 if you have the `z' library (-lz). */
#define HAVE_LIBZ 1
/* Define to 1 if you have the `lz4' library (-llz4). */
#define HAVE_LIBLZ4 0
/* Define to 1 if you have the <sys/mman.h> header file. */
#define HAVE_SYS_MMAN_H 1
/* Define to 1 if you have the <sys/resource.h> header file. */
#define HAVE_SYS_RESOURCE_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/uio.h> header file. */
#define HAVE_SYS_UIO_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the <windows.h> header file. */
#define HAVE_WINDOWS_H 0
/* Define to 1 if you target processors with SSSE3+ and have <tmmintrin.h>. */
#define SNAPPY_HAVE_SSSE3 1
/* Define to 1 if you target processors with SSE4.2 and have <crc32intrin.h>. */
#define SNAPPY_HAVE_X86_CRC32 1
/* Define to 1 if you target processors with BMI2+ and have <bmi2intrin.h>. */
#define SNAPPY_HAVE_BMI2 0
/* Define to 1 if you target processors with NEON and have <arm_neon.h>. */
#define SNAPPY_HAVE_NEON 0
/* Define to 1 if you have <arm_neon.h> and <arm_acle.h> and want to optimize
compression speed by using __crc32cw from <arm_acle.h>. */
#define SNAPPY_HAVE_NEON_CRC32 0
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
#define SNAPPY_IS_BIG_ENDIAN 0
#endif // THIRD_PARTY_SNAPPY_OPENSOURCE_CMAKE_CONFIG_H_

View File

@@ -46,23 +46,6 @@
#include <arm_neon.h>
#endif
#if SNAPPY_RVV_1 || SNAPPY_RVV_0_7
#define SNAPPY_HAVE_RVV 1
#include <riscv_vector.h>
#else
#define SNAPPY_HAVE_RVV 0
#endif
#ifdef SNAPPY_RVV_1
#define VSETVL_E8M2 __riscv_vsetvl_e8m2
#define VLE8_V_U8M2 __riscv_vle8_v_u8m2
#define VSE8_V_U8M2 __riscv_vse8_v_u8m2
#elif SNAPPY_RVV_0_7
#define VSETVL_E8M2 vsetvl_e8m2
#define VLE8_V_U8M2 vle8_v_u8m2
#define VSE8_V_U8M2 vse8_v_u8m2
#endif
#if SNAPPY_HAVE_SSSE3 || SNAPPY_HAVE_NEON
#define SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE 1
#else
@@ -127,8 +110,6 @@ inline V128 V128_Shuffle(V128 input, V128 shuffle_mask) {
}
inline V128 V128_DupChar(char c) { return vdupq_n_u8(c); }
#endif
#endif // SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE
@@ -191,10 +172,9 @@ char* CompressFragment(const char* input,
// loading from s2 + n.
//
// Separate implementation for 64-bit, little-endian cpus.
// riscv and little-endian cpu choose this routinue can be done faster too.
#if !SNAPPY_IS_BIG_ENDIAN && \
(defined(__x86_64__) || defined(_M_X64) || defined(ARCH_PPC) || \
defined(__aarch64__) || (defined(__riscv) && (__riscv_xlen == 64)))
defined(ARCH_ARM))
static inline std::pair<size_t, bool> FindMatchLength(const char* s1,
const char* s2,
const char* s2_limit,

View File

@@ -304,7 +304,6 @@ class Bits {
void operator=(const Bits&);
};
// In RISC-V, CLZ is supported by instructions from the ZBB bit-manipulation extension.
#if HAVE_BUILTIN_CTZ
inline int Bits::Log2FloorNonZero(uint32_t n) {
@@ -394,7 +393,6 @@ inline int Bits::FindLSBSetNonZero(uint32_t n) {
#endif // End portable versions.
// In RISC-V, CLZ is supported by instructions from the ZBB bit-manipulation extension.
#if HAVE_BUILTIN_CTZ
inline int Bits::FindLSBSetNonZero64(uint64_t n) {

66
snappy-stubs-public.h Normal file
View File

@@ -0,0 +1,66 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Various type stubs for the open-source version of Snappy.
//
// This file cannot include config.h, as it is included from snappy.h,
// which is a public header. Instead, snappy-stubs-public.h is generated by
// from snappy-stubs-public.h.in at configure time.
#ifndef THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_
#define THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_
#include <cstddef>
// Original cmake configure baked HAVE_SYS_UIO_H=1 on the Linux host that
// pre-generated this header; gate it on _WIN32 so cross-compiles to Windows
// fall back to the iovec definition below.
#if !defined(_WIN32) // HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif // HAVE_SYS_UIO_H
#define SNAPPY_MAJOR 1
#define SNAPPY_MINOR 2
#define SNAPPY_PATCHLEVEL 2
#define SNAPPY_VERSION \
((SNAPPY_MAJOR << 16) | (SNAPPY_MINOR << 8) | SNAPPY_PATCHLEVEL)
namespace snappy {
#if defined(_WIN32) // !HAVE_SYS_UIO_H
// Windows does not have an iovec type, yet the concept is universally useful.
// It is simple to define it ourselves, so we put it inside our own namespace.
struct iovec {
void* iov_base;
size_t iov_len;
};
#endif // !HAVE_SYS_UIO_H
} // namespace snappy
#endif // THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_

View File

@@ -74,6 +74,7 @@
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <functional>
#include <memory>
#include <string>
#include <utility>
@@ -280,8 +281,6 @@ inline char* IncrementalCopySlow(const char* src, char* op,
// 4, 5, 0, 1, 2, 3, 4, 5, 0, 1}. These byte index sequences are generated by
// calling MakePatternMaskBytes(0, 6, index_sequence<16>()) and
// MakePatternMaskBytes(16, 6, index_sequence<16>()) respectively.
template <size_t... indexes>
inline constexpr std::array<char, sizeof...(indexes)> MakePatternMaskBytes(
int index_offset, int pattern_size, index_sequence<indexes...>) {
@@ -299,6 +298,7 @@ MakePatternMaskBytesTable(int index_offset,
MakePatternMaskBytes(index_offset, pattern_sizes_minus_one + 1,
make_index_sequence</*indexes=*/sizeof(V128)>())...};
}
// This is an array of shuffle control masks that can be used as the source
// operand for PSHUFB to permute the contents of the destination XMM register
// into a repeating byte pattern.
@@ -494,6 +494,7 @@ inline char* IncrementalCopy(const char* src, char* op, char* const op_limit,
LoadPatternAndReshuffleMask(src, pattern_size);
V128 pattern = pattern_and_reshuffle_mask.first;
V128 reshuffle_mask = pattern_and_reshuffle_mask.second;
// There is at least one, and at most four 16-byte blocks. Writing four
// conditionals instead of a loop allows FDO to layout the code with
// respect to the actual probabilities of each length.
@@ -520,6 +521,7 @@ inline char* IncrementalCopy(const char* src, char* op, char* const op_limit,
LoadPatternAndReshuffleMask(src, pattern_size);
V128 pattern = pattern_and_reshuffle_mask.first;
V128 reshuffle_mask = pattern_and_reshuffle_mask.second;
// This code path is relatively cold however so we save code size
// by avoiding unrolling and vectorizing.
//
@@ -1225,7 +1227,7 @@ inline bool Copy64BytesWithPatternExtension(ptrdiff_t dst, size_t offset) {
void MemCopy64(char* dst, const void* src, size_t size) {
// Always copy this many bytes. If that's below size then copy the full 64.
constexpr int kShortMemCopy = 32;
(void)kShortMemCopy;
assert(size <= 64);
assert(std::less_equal<const void*>()(static_cast<const char*>(src) + size,
dst) ||
@@ -1244,27 +1246,6 @@ void MemCopy64(char* dst, const void* src, size_t size) {
data = _mm256_lddqu_si256(static_cast<const __m256i *>(src) + 1);
_mm256_storeu_si256(reinterpret_cast<__m256i *>(dst) + 1, data);
}
// RVV acceleration available on RISC-V when compiled with -march=rv64gcv
#elif defined(__riscv) && SNAPPY_HAVE_RVV
// Cast pointers to the type we will operate on.
unsigned char* dst_ptr = reinterpret_cast<unsigned char*>(dst);
const unsigned char* src_ptr = reinterpret_cast<const unsigned char*>(src);
size_t remaining_bytes = size;
// Loop as long as there are bytes remaining to be copied.
while (remaining_bytes > 0) {
// Set vector configuration: e8 (8-bit elements), m2 (LMUL=2).
// Use e8m2 configuration to maximize throughput.
size_t vl = VSETVL_E8M2(remaining_bytes);
// Load data from the current source pointer.
vuint8m2_t vec = VLE8_V_U8M2(src_ptr, vl);
// Store data to the current destination pointer.
VSE8_V_U8M2(dst_ptr, vec, vl);
// Update pointers and the remaining count.
src_ptr += vl;
dst_ptr += vl;
remaining_bytes -= vl;
}
#else
std::memmove(dst, src, kShortMemCopy);
// Profiling shows that nearly all copies are short.
@@ -1364,51 +1345,19 @@ inline size_t AdvanceToNextTagX86Optimized(const uint8_t** ip_p, size_t* tag) {
return tag_type;
}
SNAPPY_ATTRIBUTE_ALWAYS_INLINE
inline size_t AdvanceToNextTagRVOptimized(const uint8_t** ip_p, size_t* tag) {
const uint8_t*& ip = *ip_p;
// This section is crucial for the throughput of the decompression loop.
// The latency of an iteration is fundamentally constrained by the data chain on ip:
// ip -> c = *tag -> literal_len = c >> 2, tag_type = c & 3
// -> literal_advance = literal_len + 2, copy_advance = tag_type + 1
// -> next_ip = ip + literal_advance OR ip + copy_advance (literal vs copy)
// -> *tag = byte at (next_ip - 1); ip = next_ip
//
// Base RISC-V has no x86-style cmov and no AArch64 csinc on the same shape; this
// computes both candidate advances and both load offsets, then selects with
// (is_literal ? ... : ...). With the Zicond extension (czero.eqz / czero.nez), those
// selections typically lower to branchless conditional-zero ops instead of a
// hard-to-predict literal/copy branch, which is why this form tends to win there.
const size_t literal_len = *tag >> 2;
const size_t tag_type = *tag & 3;
const bool is_literal = (tag_type == 0);
const size_t copy_advance = tag_type + 1;
const size_t literal_advance = literal_len + 2;
const uint8_t* next_ip = is_literal ? (ip + literal_advance) : (ip + copy_advance);
*tag = is_literal ? ip[literal_advance - 1] : ip[copy_advance - 1];
ip = next_ip;
return tag_type;
}
// Extract the offset for copy-1 and copy-2 returns 0 for literals or copy-4.
inline uint32_t ExtractOffset(uint32_t val, size_t tag_type) {
// For Arm non-static storage works better. For x86 static storage is better.
// For x86 non-static storage works better. For ARM static storage is better.
// TODO: Once the array is recognized as a register, improve the
// readability for x86.
#if defined(__x86_64__)
static constexpr uint64_t kExtractMasksCombined = 0x0000FFFF00FF0000ull;
constexpr uint64_t kExtractMasksCombined = 0x0000FFFF00FF0000ull;
uint16_t result;
memcpy(&result,
reinterpret_cast<const char*>(&kExtractMasksCombined) + 2 * tag_type,
sizeof(result));
return val & result;
// For AArch64 and RISC-V, use a bit-twiddling trick to extract the mask from a
// single combined constant instead of a lookup table. The constant packs multiple
// 16-bit masks based on tag_type (see implementation below). The code calculates
// the shift amount from tag_type, right-shifts the constant to move the desired
// mask to the LSB position, then extracts it with & 0xFFFF. This branchless
// approach is often more performant on modern CPUs.
#elif defined(__aarch64__) || (defined(__riscv) && (__riscv_xlen == 64))
#elif defined(__aarch64__)
constexpr uint64_t kExtractMasksCombined = 0x0000FFFF00FF0000ull;
return val & static_cast<uint32_t>(
(kExtractMasksCombined >> (tag_type * 16)) & 0xFFFF);
@@ -1472,11 +1421,6 @@ std::pair<const uint8_t*, ptrdiff_t> DecompressBranchless(
// We never need more than 16 bits. Doing a Load16 allows the compiler
// to elide the masking operation in ExtractOffset.
next = LittleEndian::Load16(old_ip);
#elif defined(__riscv)
size_t tag_type = AdvanceToNextTagRVOptimized(&ip, &tag);
// We never need more than 16 bits. Doing a Load16 allows the compiler
// to elide the masking operation in ExtractOffset.
next = LittleEndian::Load16(old_ip);
#else
size_t tag_type = AdvanceToNextTagX86Optimized(&ip, &tag);
next = LittleEndian::Load32(old_ip);
@@ -1835,13 +1779,13 @@ static bool InternalUncompressAllTags(SnappyDecompressor* decompressor,
Writer* writer, uint32_t compressed_len,
uint32_t uncompressed_len) {
int token = 0;
Report(token, "snappy_uncompress", compressed_len, uncompressed_len);
writer->SetExpectedLength(uncompressed_len);
// Process the entire input
decompressor->DecompressAllTags(writer);
writer->Flush();
Report(token, "snappy_uncompress", compressed_len, uncompressed_len);
return (decompressor->eof() && writer->CheckLength());
}
@@ -1856,9 +1800,11 @@ size_t Compress(Source* reader, Sink* writer) {
size_t Compress(Source* reader, Sink* writer, CompressionOptions options) {
assert(options.level == 1 || options.level == 2);
int token = 0;
size_t written = 0;
size_t N = reader->Available();
assert(N <= 0xFFFFFFFFu);
const size_t uncompressed_size = N;
char ulength[Varint::kMax32];
char* p = Varint::Encode32(ulength, N);
writer->Append(ulength, p - ulength);
@@ -1911,21 +1857,22 @@ size_t Compress(Source* reader, Sink* writer, CompressionOptions options) {
// have room for us directly.
char* dest = writer->GetAppendBuffer(max_output, wmem.GetScratchOutput());
char* end = nullptr;
if (options.level == 1) {
end = internal::CompressFragment(fragment, fragment_size, dest, table,
table_size);
} else if (options.level == 2) {
end = internal::CompressFragmentDoubleHash(
fragment, fragment_size, dest, table, table_size >> 1,
table + (table_size >> 1), table_size >> 1);
}
if (options.level == 1) {
end = internal::CompressFragment(fragment, fragment_size, dest, table,
table_size);
} else if (options.level == 2) {
end = internal::CompressFragmentDoubleHash(
fragment, fragment_size, dest, table, table_size >> 1,
table + (table_size >> 1), table_size >> 1);
}
writer->Append(dest, end - dest);
written += (end - dest);
N -= num_to_read;
reader->Skip(pending_advance);
}
Report(token, "snappy_compress", written, uncompressed_size);
return written;
}

View File

@@ -64,10 +64,9 @@ namespace snappy {
// faster decompression speeds than snappy:1 and zstd:-3.
int level = DefaultCompressionLevel();
constexpr CompressionOptions() = default;
constexpr CompressionOptions(int compression_level)
: level(compression_level) {}
constexpr CompressionOptions() = default;
constexpr CompressionOptions(int compression_level)
: level(compression_level) {}
static constexpr int MinCompressionLevel() { return 1; }
static constexpr int MaxCompressionLevel() { return 2; }
static constexpr int DefaultCompressionLevel() { return 1; }
@@ -159,7 +158,6 @@ namespace snappy {
// RawCompress(input, input_length, output, &output_length);
// ... Process(output, output_length) ...
// delete [] output;
// First version is to preserve ABI.
void RawCompress(const char* input, size_t input_length, char* compressed,
size_t* compressed_length);
void RawCompress(const char* input, size_t input_length, char* compressed,
@@ -168,7 +166,6 @@ namespace snappy {
// Same as `RawCompress` above but taking an `iovec` array as input. Note that
// `uncompressed_length` is the total number of bytes to be read from the
// elements of `iov` (_not_ the number of elements in `iov`).
// First version is to preserve ABI.
void RawCompressFromIOVec(const struct iovec* iov, size_t uncompressed_length,
char* compressed, size_t* compressed_length);
void RawCompressFromIOVec(const struct iovec* iov, size_t uncompressed_length,