Compare commits

..

3 Commits

Author SHA1 Message Date
Daniel Lemire 8e85352df4 Merge branch 'master' into parse_string_if_needed 2026-01-21 10:10:42 -05:00
Daniel Lemire 403b8bfb91 let us be careful and not change the API 2024-07-11 19:36:12 -04:00
Daniel Lemire 76f45a0c4b fix: add parse_string_if_needed function 2024-07-11 17:57:05 -04:00
66 changed files with 273 additions and 1081 deletions
+5 -5
View File
@@ -19,11 +19,11 @@ jobs:
sudo apt-get install -y cmake make g++-riscv64-linux-gnu qemu-user-static clang-18
- name: Build
run: |
CC=clang-18 CXX=clang++-18 CFLAGS="--target=riscv64-linux-gnu -march=rv64gcv_zvbb" CXXFLAGS="${CFLAGS}" \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DSIMDJSON_DEVELOPER_MODE=ON -B build
cmake --build build/ -j$(nproc) --config Release
CXX=clang++-18 CXXFLAGS="--target=riscv64-linux-gnu -march=rv64gcv_zvbb" \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build/ -j$(nproc)
- name: Test VLEN=1024
run: |
QEMU_LD_PREFIX="/usr/riscv64-linux-gnu" \
QEMU_CPU="rv64,v=on,zvbb=on,vlen=1024,rvv_ta_all_1s=on,rvv_ma_all_1s=on" \
export QEMU_LD_PREFIX="/usr/riscv64-linux-gnu"
export QEMU_CPU="rv64,v=on,zvbb=on,vlen=1024,rvv_ta_all_1s=on,rvv_ma_all_1s=on"
ctest --timeout 1800 --output-on-failure --test-dir build -j $(nproc)
+8 -3
View File
@@ -19,6 +19,11 @@ jobs:
sudo apt-get install -y cmake make g++-riscv64-linux-gnu qemu-user-static clang-17
- name: Build
run: |
CC=clang-17 CXX=clang++-17 CFLAGS="--target=riscv64-linux-gnu -march=rv64gcv" CXXFLAGS="${CFLAGS}" \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DSIMDJSON_DEVELOPER_MODE=ON -B build
cmake --build build/ -j$(nproc) --config Release
CXX=clang++-17 CXXFLAGS="--target=riscv64-linux-gnu -march=rv64gcv" \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build/ -j$(nproc)
- name: Test VLEN=128
run: |
export QEMU_LD_PREFIX="/usr/riscv64-linux-gnu"
export QEMU_CPU="rv64,v=on,vlen=128,rvv_ta_all_1s=on,rvv_ma_all_1s=on"
ctest --timeout 1800 --output-on-failure --test-dir build -j $(nproc)
-39
View File
@@ -1,39 +0,0 @@
name: Ubuntu rvv VLEN=128 (clang 20)
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install packages
run: |
sudo apt-get update -q -y
sudo apt-get install -y cmake make g++-riscv64-linux-gnu qemu-user-static clang-20
- name: Build
run: |
CC=clang-20 CXX=clang++-20 CFLAGS="--target=riscv64-linux-gnu -march=rv64gcv" CXXFLAGS="${CFLAGS}" \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DSIMDJSON_DEVELOPER_MODE=ON -B build
cmake --build build/ -j$(nproc) --config Release
- name: Test VLEN=128
run: |
QEMU_LD_PREFIX="/usr/riscv64-linux-gnu" \
QEMU_CPU="rv64,v=on,vlen=128,rvv_ta_all_1s=on,rvv_ma_all_1s=on" \
ctest --timeout 1800 --output-on-failure --test-dir build -j $(nproc)
- name: Build VLS
run: |
CC=clang-20 CXX=clang++-20 CFLAGS="--target=riscv64-linux-gnu -march=rv64gcv_zvl128b_zba_zbb_zbc -mrvv-vector-bits=zvl" CXXFLAGS="${CFLAGS}" \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DSIMDJSON_DEVELOPER_MODE=ON -B build-vls
cmake --build build-vls/ -j$(nproc) --config Release
- name: Test VLEN=128 VLS
run: |
QEMU_LD_PREFIX="/usr/riscv64-linux-gnu" \
QEMU_CPU="rv64,v=on,zba=on,zbb=on,zbc=on,vlen=128,rvv_ta_all_1s=on,rvv_ma_all_1s=on" \
ctest --timeout 1800 --output-on-failure --test-dir build-vls -j $(nproc)
+5 -15
View File
@@ -19,21 +19,11 @@ jobs:
sudo apt-get install -y cmake make g++-14-riscv64-linux-gnu qemu-user-static
- name: Build
run: |
CC=riscv64-linux-gnu-gcc-14 CXX=riscv64-linux-gnu-g++-14 CFLAGS=-march=rv64gcv CXXFLAGS="${CFLAGS}" \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DSIMDJSON_DEVELOPER_MODE=ON -B build
cmake --build build/ -j$(nproc) --config Release
CXX=riscv64-linux-gnu-g++-14 CXXFLAGS=-march=rv64gcv \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build/ -j$(nproc)
- name: Test VLEN=256
run: |
QEMU_LD_PREFIX="/usr/riscv64-linux-gnu" \
QEMU_CPU="rv64,v=on,zvbb=on,vlen=256,rvv_ta_all_1s=on,rvv_ma_all_1s=on" \
export QEMU_LD_PREFIX="/usr/riscv64-linux-gnu"
export QEMU_CPU="rv64,v=on,zvbb=on,vlen=256,rvv_ta_all_1s=on,rvv_ma_all_1s=on"
ctest --timeout 1800 --output-on-failure --test-dir build -j $(nproc)
- name: Build VLS
run: |
CC=riscv64-linux-gnu-gcc-14 CXX=riscv64-linux-gnu-g++-14 CFLAGS="-march=rv64gcv_zvl256b -mrvv-vector-bits=zvl" CXXFLAGS="${CFLAGS}" \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DSIMDJSON_DEVELOPER_MODE=ON -B build-vls
cmake --build build-vls/ -j$(nproc) --config Release
- name: Test VLEN=256 VLS
run: |
QEMU_LD_PREFIX="/usr/riscv64-linux-gnu" \
QEMU_CPU="rv64,v=on,zvbb=on,vlen=256,rvv_ta_all_1s=on,rvv_ma_all_1s=on" \
ctest --timeout 1800 --output-on-failure --test-dir build-vls -j $(nproc)
-39
View File
@@ -1,39 +0,0 @@
name: Ubuntu rvv VLEN=512 (clang 19)
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install packages
run: |
sudo apt-get update -q -y
sudo apt-get install -y cmake make g++-riscv64-linux-gnu qemu-user-static clang-19
- name: Build
run: |
CC=clang-19 CXX=clang++-19 CFLAGS="--target=riscv64-linux-gnu -march=rv64gcv" CXXFLAGS="${CFLAGS}" \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DSIMDJSON_DEVELOPER_MODE=ON -B build
cmake --build build/ -j$(nproc) --config Release
- name: Test VLEN=512
run: |
QEMU_LD_PREFIX="/usr/riscv64-linux-gnu" \
QEMU_CPU="rv64,v=on,vlen=512,rvv_ta_all_1s=on,rvv_ma_all_1s=on" \
ctest --timeout 1800 --output-on-failure --test-dir build -j $(nproc)
- name: Build VLS
run: |
CC=clang-19 CXX=clang++-19 CFLAGS="--target=riscv64-linux-gnu -march=rv64gcv_zvl512b_zba_zbb_zbc -mrvv-vector-bits=zvl" CXXFLAGS="${CFLAGS}" \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DSIMDJSON_DEVELOPER_MODE=ON -B build-vls
cmake --build build-vls/ -j$(nproc) --config Release
- name: Test VLEN=512 VLS
run: |
QEMU_LD_PREFIX="/usr/riscv64-linux-gnu" \
QEMU_CPU="rv64,v=on,zba=on,zbb=on,zbc=on,vlen=512,rvv_ta_all_1s=on,rvv_ma_all_1s=on" \
ctest --timeout 1800 --output-on-failure --test-dir build-vls -j $(nproc)
-1
View File
@@ -428,7 +428,6 @@ namespace {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
static_assert(NUM_CHUNKS == 4, "ARM kernel should use four registers per 64-byte block.");
const simd8<T> chunks[NUM_CHUNKS];
template<int idx> simd8<uint8_t> get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8<T>(); }
simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
+5 -2
View File
@@ -17,6 +17,7 @@ using namespace simd;
struct backslash_and_quote {
public:
static constexpr uint32_t BYTES_PROCESSED = 32;
// We only copy if dst is non-null.
simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
@@ -34,8 +35,10 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
simd8<uint8_t> v0(src);
simd8<uint8_t> v1(src + sizeof(v0));
v0.store(dst);
v1.store(dst + sizeof(v0));
if(dst != nullptr) {
v0.store(dst);
v1.store(dst + sizeof(v0));
}
// Getting a 64-bit bitmask is much cheaper than multiple 16-bit bitmasks on ARM; therefore, we
// smash them together into a 64-byte mask and get the bitmask from there.
-2
View File
@@ -24,8 +24,6 @@
#include "simdjson/lasx.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lsx)
#include "simdjson/lsx.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv_vls)
#include "simdjson/rvv-vls.h"
#else
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
#endif
-2
View File
@@ -21,8 +21,6 @@ namespace simdjson {
namespace lsx {}
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
namespace lasx {}
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv_vls)
namespace rvv_vls {}
#else
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
#endif
+1 -3
View File
@@ -24,8 +24,6 @@
#include "simdjson/lsx/builder.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
#include "simdjson/lasx/builder.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv_vls)
#include "simdjson/rvv-vls/builder.h"
#else
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
#endif
@@ -39,4 +37,4 @@ namespace simdjson {
namespace builder = SIMDJSON_BUILTIN_IMPLEMENTATION::builder;
} // namespace simdjson
#endif // SIMDJSON_BUILTIN_BUILDER_H
#endif // SIMDJSON_BUILTIN_BUILDER_H
+1 -3
View File
@@ -23,8 +23,6 @@
#include "simdjson/lsx/implementation.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
#include "simdjson/lasx/implementation.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv_vls)
#include "simdjson/rvv-vls/implementation.h"
#else
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
#endif
@@ -41,4 +39,4 @@ namespace simdjson {
const implementation * builtin_implementation();
} // namespace simdjson
#endif // SIMDJSON_BUILTIN_IMPLEMENTATION_H
#endif // SIMDJSON_BUILTIN_IMPLEMENTATION_H
+1 -3
View File
@@ -24,8 +24,6 @@
#include "simdjson/lsx/ondemand.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
#include "simdjson/lasx/ondemand.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(rvv_vls)
#include "simdjson/rvv-vls/ondemand.h"
#else
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
#endif
@@ -39,4 +37,4 @@ namespace simdjson {
namespace ondemand = SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand;
} // namespace simdjson
#endif // SIMDJSON_BUILTIN_ONDEMAND_H
#endif // SIMDJSON_BUILTIN_ONDEMAND_H
@@ -13,6 +13,7 @@ namespace {
struct backslash_and_quote {
public:
static constexpr uint32_t BYTES_PROCESSED = 1;
// We only copy if dst is non-null.
simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
simdjson_inline bool has_quote_first() { return c == '"'; }
@@ -25,7 +26,9 @@ public:
simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
// store to dest unconditionally - we can overwrite the bits we don't like later
dst[0] = src[0];
if(dst != nullptr) {
dst[0] = src[0];
}
return { src[0] };
}
+1 -3
View File
@@ -21,8 +21,6 @@
#include "simdjson/lasx/begin.h"
#elif SIMDJSON_IMPLEMENTATION_LSX
#include "simdjson/lsx/begin.h"
#elif SIMDJSON_IMPLEMENTATION_RVV_VLS
#include "simdjson/rvv-vls/begin.h"
#elif SIMDJSON_IMPLEMENTATION_FALLBACK
#include "simdjson/fallback/begin.h"
#else
@@ -50,4 +48,4 @@ enum class number_type {
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#endif // SIMDJSON_GENERIC_BASE_H
#endif // SIMDJSON_GENERIC_BASE_H
@@ -40,6 +40,7 @@ public:
simdjson_warn_unused error_code stage1(const uint8_t *buf, size_t len, stage1_mode partial) noexcept final;
simdjson_warn_unused error_code stage2(dom::document &doc) noexcept final;
simdjson_warn_unused error_code stage2_next(dom::document &doc) noexcept final;
simdjson_warn_unused std::pair<const uint8_t *,bool> parse_string_if_needed(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept final;
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept final;
simdjson_warn_unused uint8_t *parse_wobbly_string(const uint8_t *src, uint8_t *dst) const noexcept final;
inline simdjson_warn_unused error_code set_capacity(size_t capacity) noexcept final;
@@ -364,7 +364,7 @@ simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_js
#endif // !defined(SIMDJSON_VISUAL_STUDIO) && !defined(SIMDJSON_CLANG_VISUAL_STUDIO)
return result;
#else
return parser->unescape(in, _string_buf_loc, allow_replacement);
return parser->unescape_maybe(in, _string_buf_loc, allow_replacement);
#endif
}
@@ -179,6 +179,20 @@ simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
}
}
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_maybe(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
std::pair<const uint8_t *, bool> result = implementation->parse_string_if_needed(in.buf, dst, allow_replacement);
const uint8_t *end = result.first;
bool copied = result.second;
if (!end) { return STRING_ERROR; }
if(copied) {
std::string_view strresult(reinterpret_cast<const char *>(dst), end-dst);
dst = const_cast<uint8_t *>(end);
return strresult;
}
// fast path, no copy was made!!!
return std::string_view(reinterpret_cast<const char *>(in.buf), end-in.buf);
}
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
if (!end) { return STRING_ERROR; }
@@ -334,6 +334,32 @@ public:
*/
simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
/**
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer if
* needed. If no escaping is done, the string is returned as is and dst is not not changed.
* The result must be valid UTF-8.
* The provided pointer is advanced to the end of the string by reference if a copy is needed,
* and a string_view instance
* is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
* as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
*
* This unescape_maybe function is a low-level function. If you want a more user-friendly approach, you should
* avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
* instead of get_raw_json_string()).
*
* ## IMPORTANT: string_view lifetime
*
* The string_view is only valid as long as the bytes in dst.
*
* @param raw_json_string input
* @param dst A pointer to a buffer at least large enough to write this string as well as
* an additional SIMDJSON_PADDING bytes.
* @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
* @return A string_view pointing at the unescaped string in dst
* @error STRING_ERROR if escapes are incorrect.
*/
simdjson_inline simdjson_result<std::string_view> unescape_maybe(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
/**
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
* The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
+2 -5
View File
@@ -198,17 +198,14 @@ public:
* simdjson::ondemand::document doc = parser.iterate(json);
* auto view = doc["deviceId"].get_string(true);
*
* @returns An UTF-8 string. The string is stored in the parser when escaping was needed
* and will be invalidated the next
* time it parses a document or when it is destroyed. If no escaping was needed,
* the string_view points directly into the original JSON buffer.
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
* time it parses a document or when it is destroyed.
* @returns INCORRECT_TYPE if the JSON value is not a string.
*/
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
/**
* Attempts to fill the provided std::string reference with the parsed value of the current string.
* The data is stored into the provided std::string instance.
*
* The string is guaranteed to be valid UTF-8.
*
@@ -510,49 +510,14 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse
}
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
// Optimization strategy:
// We expect that most strings do not have escape characters, and most are short.
// So we can quickly check for backslashes and if there are none, we can just return a string_view
// into the original JSON buffer. There is no need to copy or unescape.
// Fast path: check for backslash in the string
// It may seem that this function is odd in that it scans the string even if a
// backslash is found early. However, we expect that in most strings there will be no backslash,
// so we optimize for that case. The compiler knows to expect a full scan and it can optimize for it.
auto has_backslash_fast = [](std::string_view s) noexcept {
for(const char c : s) {
if(c == '\\') {
return true;
}
}
return false;
};
std::string_view string_with_quotes(reinterpret_cast<const char*>(peek_start()), peek_start_length());
if(string_with_quotes.front() != '"') {
return incorrect_type_error("Not a string");
}
if(!has_backslash_fast(string_with_quotes)) {
// Find the ending quote
size_t len = string_with_quotes.size();
while(string_with_quotes[len - 1] != '"') {
len--;
}
// At this point len is 2 or more
return std::string_view(string_with_quotes.data() + 1, len - 2);
}
// Slow path: we have a backslash, so we need to unescape
return get_raw_json_string().unescape(json_iter(), allow_replacement);
}
template <typename string_type>
simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
std::string_view content;
// Save the string buffer location so that we can restore it after get_string
auto saved_string_buf_loc = _json_iter->string_buf_loc();
SIMDJSON_TRY(get_string(allow_replacement).get(content));
auto err = get_string(allow_replacement).get(content);
if (err) { return err; }
receiver = content;
// Restore the string buffer location, effectively discarding any temporary string storage
_json_iter->string_buf_loc() = saved_string_buf_loc;
return SUCCESS;
}
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
@@ -687,19 +652,14 @@ simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool che
return num;
}
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
// We could optimize for the no-escape case here as well, but root strings
// are less common so we do the simple thing for now.
return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
}
template <typename string_type>
simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
std::string_view content;
// Save the string buffer location so that we can restore it after get_string
auto saved_string_buf_loc = _json_iter->string_buf_loc();
SIMDJSON_TRY(get_root_string(check_trailing, allow_replacement).get(content));
auto err = get_root_string(check_trailing, allow_replacement).get(content);
if (err) { return err; }
receiver = content;
// Restore the string buffer location, effectively discarding any temporary string storage
_json_iter->string_buf_loc() = saved_string_buf_loc;
return SUCCESS;
}
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
-1
View File
@@ -300,7 +300,6 @@ namespace simd {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
static_assert(NUM_CHUNKS == 2, "Haswell kernel should use two registers per 64-byte block.");
const simd8<T> chunks[NUM_CHUNKS];
template<int idx> simd8<uint8_t> get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8<T>(); }
simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
@@ -17,6 +17,7 @@ using namespace simd;
struct backslash_and_quote {
public:
static constexpr uint32_t BYTES_PROCESSED = 32;
// We only copy if dst is non-null.
simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
@@ -34,7 +35,9 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
simd8<uint8_t> v(src);
// store to dest unconditionally - we can overwrite the bits we don't like later
v.store(dst);
if(dst != nullptr) {
v.store(dst);
}
return {
static_cast<uint32_t>((v == '\\').to_bitmask()), // bs_bits
static_cast<uint32_t>((v == '"').to_bitmask()), // quote_bits
-1
View File
@@ -322,7 +322,6 @@ namespace simd {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
static_assert(NUM_CHUNKS == 1, "Icelake kernel should use one register per 64-byte block.");
const simd8<T> chunks[NUM_CHUNKS];
template<int idx> simd8<uint8_t> get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8<T>(); }
simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
@@ -17,6 +17,7 @@ using namespace simd;
struct backslash_and_quote {
public:
static constexpr uint32_t BYTES_PROCESSED = 64;
// We only copy if dst is non-null.
simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
@@ -34,7 +35,9 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
simd8<uint8_t> v(src);
// store to dest unconditionally - we can overwrite the bits we don't like later
v.store(dst);
if(dst != nullptr) {
v.store(dst);
}
return {
static_cast<uint64_t>(v == '\\'), // bs_bits
static_cast<uint64_t>(v == '"'), // quote_bits
+1 -10
View File
@@ -12,8 +12,6 @@
#define SIMDJSON_IMPLEMENTATION_ID_westmere 6
#define SIMDJSON_IMPLEMENTATION_ID_lsx 7
#define SIMDJSON_IMPLEMENTATION_ID_lasx 8
//#define SIMDJSON_IMPLEMENTATION_ID_rvv 9
#define SIMDJSON_IMPLEMENTATION_ID_rvv_vls 10
#define SIMDJSON_IMPLEMENTATION_ID_FOR(IMPL) SIMDJSON_CAT(SIMDJSON_IMPLEMENTATION_ID_, IMPL)
#define SIMDJSON_IMPLEMENTATION_ID SIMDJSON_IMPLEMENTATION_ID_FOR(SIMDJSON_IMPLEMENTATION)
@@ -128,14 +126,9 @@
#endif
#define SIMDJSON_CAN_ALWAYS_RUN_LSX (SIMDJSON_IMPLEMENTATION_LSX)
#define SIMDJSON_CAN_ALWAYS_RUN_RVV_VLS SIMDJSON_IS_RVV_VLS
#ifndef SIMDJSON_IMPLEMENTATION_RVV_VLS
#define SIMDJSON_IMPLEMENTATION_RVV_VLS SIMDJSON_CAN_ALWAYS_RUN_RVV_VLS
#endif
// Default Fallback to on unless a builtin implementation has already been selected.
#ifndef SIMDJSON_IMPLEMENTATION_FALLBACK
#if SIMDJSON_CAN_ALWAYS_RUN_ARM64 || SIMDJSON_CAN_ALWAYS_RUN_ICELAKE || SIMDJSON_CAN_ALWAYS_RUN_HASWELL || SIMDJSON_CAN_ALWAYS_RUN_WESTMERE || SIMDJSON_CAN_ALWAYS_RUN_PPC64 || SIMDJSON_CAN_ALWAYS_RUN_LSX || SIMDJSON_CAN_ALWAYS_RUN_LASX || SIMDJSON_CAN_ALWAYS_RUN_RVV_VLS
#if SIMDJSON_CAN_ALWAYS_RUN_ARM64 || SIMDJSON_CAN_ALWAYS_RUN_ICELAKE || SIMDJSON_CAN_ALWAYS_RUN_HASWELL || SIMDJSON_CAN_ALWAYS_RUN_WESTMERE || SIMDJSON_CAN_ALWAYS_RUN_PPC64 || SIMDJSON_CAN_ALWAYS_RUN_LSX || SIMDJSON_CAN_ALWAYS_RUN_LASX
// if anything at all except fallback can always run, then disable fallback.
#define SIMDJSON_IMPLEMENTATION_FALLBACK 0
#else
@@ -161,8 +154,6 @@
#define SIMDJSON_BUILTIN_IMPLEMENTATION lsx
#elif SIMDJSON_CAN_ALWAYS_RUN_LASX
#define SIMDJSON_BUILTIN_IMPLEMENTATION lasx
#elif SIMDJSON_CAN_ALWAYS_RUN_RVV_VLS
#define SIMDJSON_BUILTIN_IMPLEMENTATION rvv_vls
#elif SIMDJSON_CAN_ALWAYS_RUN_FALLBACK
#define SIMDJSON_BUILTIN_IMPLEMENTATION fallback
#else
@@ -4,6 +4,7 @@
#include "simdjson/base.h"
#include "simdjson/error.h"
#include <memory>
#include <utility>
namespace simdjson {
@@ -102,6 +103,24 @@ public:
*/
simdjson_warn_unused virtual error_code stage2_next(dom::document &doc) noexcept = 0;
/**
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
* must be an unescaped quote terminating the string. It returns the final output
* position as pointer. In case of error (e.g., the string has bad escaped codes),
* then null_ptr is returned. If no escaping was required, then no copy is made.
* It is assumed that the output buffer is large
* enough to store the unescapedstring + SIMDJSON_PADDING bytes.
*
* Overridden by each implementation.
*
* @param str pointer to the beginning of a valid UTF-8 JSON string, must end with an unescaped quote.
* @param dst pointer to a destination buffer, it must point a region in memory of sufficient size.
* @param allow_replacement whether we allow a replacement character when the UTF-8 contains unmatched surrogate pairs.
* @return end of the of the written region (exclusive) or nullptr in case of error coupled with a Boolean telling you if a copy was made
*/
simdjson_warn_unused virtual std::pair<const uint8_t *,bool> parse_string_if_needed(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept = 0;
/**
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
* must be an unescaped quote terminating the string. It returns the final output
@@ -69,8 +69,6 @@ enum instruction_set {
AVX512VBMI2 = 0x10000,
LSX = 0x20000,
LASX = 0x40000,
//RVV = 0x80000,
RVV_VLS = 0x100000,
};
} // namespace internal
-1
View File
@@ -303,7 +303,6 @@ namespace simd {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
static_assert(NUM_CHUNKS == 2, "LASX kernel should use two registers per 64-byte block.");
const simd8<T> chunks[NUM_CHUNKS];
template<int idx> simd8<uint8_t> get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8<T>(); }
simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
+4 -1
View File
@@ -17,6 +17,7 @@ using namespace simd;
struct backslash_and_quote {
public:
static constexpr uint32_t BYTES_PROCESSED = 32;
// We only copy if dst is non-null.
simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
@@ -33,7 +34,9 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
// SIMDJSON_PADDING of padding
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
simd8<uint8_t> v(src);
v.store(dst);
if(dst != nullptr) {
v.store(dst);
}
return {
static_cast<uint32_t>((v == '\\').to_bitmask()), // bs_bits
static_cast<uint32_t>((v == '"').to_bitmask()), // quote_bits
-1
View File
@@ -260,7 +260,6 @@ namespace simd {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
static_assert(NUM_CHUNKS == 4, "LSX kernel should use four registers per 64-byte block.");
const simd8<T> chunks[NUM_CHUNKS];
template<int idx> simd8<uint8_t> get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8<T>(); }
simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
+5 -2
View File
@@ -17,6 +17,7 @@ using namespace simd;
struct backslash_and_quote {
public:
static constexpr uint32_t BYTES_PROCESSED = 32;
// We only copy if dst is non-null.
simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
@@ -34,8 +35,10 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
simd8<uint8_t> v0(src);
simd8<uint8_t> v1(src + sizeof(v0));
v0.store(dst);
v1.store(dst + sizeof(v0));
if(dst != nullptr) {
v0.store(dst);
v1.store(dst + sizeof(v0));
}
// Getting a 64-bit bitmask is much cheaper than multiple 16-bit bitmasks on LSX; therefore, we
// smash them together into a 64-byte mask and get the bitmask from there.
+10 -8
View File
@@ -45,20 +45,22 @@ using std::size_t;
#define SIMDJSON_IS_ARM64 1
#elif defined(__riscv) && __riscv_xlen == 64
#define SIMDJSON_IS_RISCV64 1
#if __riscv_v_intrinsic >= 11000
#define SIMDJSON_HAS_RVV_INTRINSICS 1
#endif
#if SIMDJSON_HAS_RVV_INTRINSICS && __riscv_vector && __riscv_v_min_vlen >= 128 && __riscv_v_elen >= 64
#define SIMDJSON_IS_RVV 1 // RISC-V V extension
#endif
#define SIMDJSON_HAS_ZVBB_INTRINSICS \
0 // there is currently no way to detect this
// current toolchains don't support fixed-size SIMD types that don't match VLEN directly
#if __riscv_v_fixed_vlen >= 128 && __riscv_v_fixed_vlen <= 512
#define SIMDJSON_IS_RVV_VLS 1
#if SIMDJSON_HAS_RVV_INTRINSICS && __riscv_vector && \
__riscv_v_min_vlen >= 128 && __riscv_v_elen >= 64
// RISC-V V extension
#define SIMDJSON_IS_RVV 1
#if SIMDJSON_HAS_ZVBB_INTRINSICS && __riscv_zvbb >= 1000000
// RISC-V Vector Basic Bit-manipulation
#define SIMDJSON_IS_ZVBB 1
#endif
#endif
#elif defined(__loongarch_lp64)
#define SIMDJSON_IS_LOONGARCH64 1
#if defined(__loongarch_sx) && defined(__loongarch_asx)
-1
View File
@@ -397,7 +397,6 @@ template <typename T> struct simd8x64 {
static_assert(NUM_CHUNKS == 4,
"PPC64 kernel should use four registers per 64-byte block.");
const simd8<T> chunks[NUM_CHUNKS];
template<int idx> simd8<uint8_t> get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8<T>(); }
simd8x64(const simd8x64<T> &o) = delete; // no copy allowed
simd8x64<T> &
+5 -2
View File
@@ -17,6 +17,7 @@ using namespace simd;
struct backslash_and_quote {
public:
static constexpr uint32_t BYTES_PROCESSED = 32;
// We only copy if dst is non-null.
simdjson_inline backslash_and_quote
copy_and_find(const uint8_t *src, uint8_t *dst);
@@ -44,8 +45,10 @@ backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
"SIMDJSON_PADDING bytes");
simd8<uint8_t> v0(src);
simd8<uint8_t> v1(src + sizeof(v0));
v0.store(dst);
v1.store(dst + sizeof(v0));
if(dst != nullptr) {
v0.store(dst);
v1.store(dst + sizeof(v0));
}
// Getting a 64-bit bitmask is much cheaper than multiple 16-bit bitmasks on
// PPC; therefore, we smash them together into a 64-byte mask and get the
-9
View File
@@ -1,9 +0,0 @@
#ifndef SIMDJSON_RVV_VLS_H
#define SIMDJSON_RVV_VLS_H
#include "simdjson/rvv-vls/begin.h"
#include "simdjson/generic/amalgamated.h"
#include "simdjson/rvv-vls/end.h"
#endif // SIMDJSON_RVV_VLS_H
-19
View File
@@ -1,19 +0,0 @@
#ifndef SIMDJSON_RVV_VLS_BASE_H
#define SIMDJSON_RVV_VLS_BASE_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
/**
* RVV-VLS implementation.
*/
namespace rvv_vls {
class implementation;
} // namespace rvv_vls
} // namespace simdjson
#endif // SIMDJSON_RVV_VLS_BASE_H
-10
View File
@@ -1,10 +0,0 @@
#define SIMDJSON_IMPLEMENTATION rvv_vls
#include "simdjson/rvv-vls/base.h"
#include "simdjson/rvv-vls/intrinsics.h"
#include "simdjson/rvv-vls/bitmanipulation.h"
#include "simdjson/rvv-vls/bitmask.h"
#include "simdjson/rvv-vls/simd.h"
#include "simdjson/rvv-vls/stringparsing_defs.h"
#include "simdjson/rvv-vls/numberparsing_defs.h"
#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1
@@ -1,48 +0,0 @@
#ifndef SIMDJSON_RVV_VLS_BITMANIPULATION_H
#define SIMDJSON_RVV_VLS_BITMANIPULATION_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/rvv-vls/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
namespace rvv_vls {
namespace {
// We sometimes call trailing_zero on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
SIMDJSON_NO_SANITIZE_UNDEFINED
// This function can be used safely even if not all bytes have been
// initialized.
// See issue https://github.com/simdjson/simdjson/issues/1965
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_inline int trailing_zeroes(uint64_t input_num) {
return __builtin_ctzll(input_num);
}
/* result might be undefined when input_num is zero */
simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return input_num & (input_num-1);
}
/* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) {
return __builtin_clzll(input_num);
}
simdjson_inline long long int count_ones(uint64_t input_num) {
return __builtin_popcountll(input_num);
}
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
uint64_t *result) {
return __builtin_uaddll_overflow(value1, value2,
reinterpret_cast<unsigned long long *>(result));
}
} // unnamed namespace
} // namespace rvv_vls
} // namespace simdjson
#endif // SIMDJSON_RVV_VLS_BITMANIPULATION_H
-39
View File
@@ -1,39 +0,0 @@
#ifndef SIMDJSON_RVV_VLS_BITMASK_H
#define SIMDJSON_RVV_VLS_BITMASK_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/rvv-vls/base.h"
#include "simdjson/rvv-vls/intrinsics.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
namespace rvv_vls {
namespace {
//
// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
//
// For example, prefix_xor(00100100) == 00011100
//
simdjson_inline uint64_t prefix_xor(uint64_t bitmask) {
#if __riscv_zbc
return __riscv_clmul_64(bitmask, ~(uint64_t)0);
#elif __riscv_zvbc
return __riscv_vmv_x(__riscv_vclmul(__riscv_vmv_s_x_u64m1(bitmask, 1), ~(uint64_t)0, 1));
#else
bitmask ^= bitmask << 1;
bitmask ^= bitmask << 2;
bitmask ^= bitmask << 4;
bitmask ^= bitmask << 8;
bitmask ^= bitmask << 16;
bitmask ^= bitmask << 32;
#endif
return bitmask;
}
} // unnamed namespace
} // namespace rvv_vls
} // namespace simdjson
#endif // SIMDJSON_RVV_VLS_BITMASK_H
-8
View File
@@ -1,8 +0,0 @@
#ifndef SIMDJSON_RVV_VLS_BUILDER_H
#define SIMDJSON_RVV_VLS_BUILDER_H
#include "simdjson/rvv-vls/begin.h"
#include "simdjson/generic/builder/amalgamated.h"
#include "simdjson/rvv-vls/end.h"
#endif // SIMDJSON_RVV_VLS_BUILDER_H
-5
View File
@@ -1,5 +0,0 @@
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/rvv-vls/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
#undef SIMDJSON_IMPLEMENTATION
-34
View File
@@ -1,34 +0,0 @@
#ifndef SIMDJSON_RVV_VLS_IMPLEMENTATION_H
#define SIMDJSON_RVV_VLS_IMPLEMENTATION_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/rvv-vls/base.h"
#include "simdjson/implementation.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
namespace rvv_vls {
/**
* @private
*/
class implementation final : public simdjson::implementation {
public:
simdjson_inline implementation() : simdjson::implementation(
"rvv_vls",
"RISC-V V extension",
0
) {}
simdjson_warn_unused error_code create_dom_parser_implementation(
size_t capacity,
size_t max_length,
std::unique_ptr<simdjson::internal::dom_parser_implementation>& dst
) const noexcept final;
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
};
} // namespace rvv_vls
} // namespace simdjson
#endif // SIMDJSON_RVV_VLS_IMPLEMENTATION_H
-32
View File
@@ -1,32 +0,0 @@
#ifndef SIMDJSON_RVV_VLS_INTRINSICS_H
#define SIMDJSON_RVV_VLS_INTRINSICS_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/rvv-vls/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
#include <riscv_vector.h>
#define simdutf_vrgather_u8m1x2(tbl, idx) \
__riscv_vcreate_v_u8m1_u8m2( \
__riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m2_u8m1(idx, 0), \
__riscv_vsetvlmax_e8m1()), \
__riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m2_u8m1(idx, 1), \
__riscv_vsetvlmax_e8m1()))
#define simdutf_vrgather_u8m1x4(tbl, idx) \
__riscv_vcreate_v_u8m1_u8m4( \
__riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 0), \
__riscv_vsetvlmax_e8m1()), \
__riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 1), \
__riscv_vsetvlmax_e8m1()), \
__riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 2), \
__riscv_vsetvlmax_e8m1()), \
__riscv_vrgather_vv_u8m1(tbl, __riscv_vget_v_u8m4_u8m1(idx, 3), \
__riscv_vsetvlmax_e8m1()))
#if __riscv_zbc
#include <riscv_bitmanip.h>
#endif
#endif // SIMDJSON_RVV_VLS_INTRINSICS_H
@@ -1,56 +0,0 @@
#ifndef SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H
#define SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/rvv-vls/base.h"
#include "simdjson/internal/numberparsing_tables.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
#include <cstring>
#ifdef JSON_TEST_NUMBERS // for unit testing
void found_invalid_number(const uint8_t *buf);
void found_integer(int64_t result, const uint8_t *buf);
void found_unsigned_integer(uint64_t result, const uint8_t *buf);
void found_float(double result, const uint8_t *buf);
#endif
namespace simdjson {
namespace rvv_vls {
namespace numberparsing {
// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
/** @private */
static simdjson_inline uint32_t parse_eight_digits_unrolled(const char *chars) {
uint64_t val;
#if __riscv_misaligned_fast
memcpy(&val, chars, sizeof(uint64_t));
#else
val = __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vlmul_ext_u8m1(__riscv_vle8_v_u8mf2((uint8_t*)chars, 8))));
#endif
val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
}
/** @private */
static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
return parse_eight_digits_unrolled(reinterpret_cast<const char *>(chars));
}
/** @private */
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
answer.high = uint64_t(r >> 64);
return answer;
}
} // namespace numberparsing
} // namespace rvv_vls
} // namespace simdjson
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif // SIMDJSON_RVV_VLS_NUMBERPARSING_DEFS_H
-8
View File
@@ -1,8 +0,0 @@
#ifndef SIMDJSON_RVV_VLS_ONDEMAND_H
#define SIMDJSON_RVV_VLS_ONDEMAND_H
#include "simdjson/rvv-vls/begin.h"
#include "simdjson/generic/ondemand/amalgamated.h"
#include "simdjson/rvv-vls/end.h"
#endif // SIMDJSON_RVV_VLS_ONDEMAND_H
-370
View File
@@ -1,370 +0,0 @@
#ifndef SIMDJSON_RVV_VLS_SIMD_H
#define SIMDJSON_RVV_VLS_SIMD_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/rvv-vls/base.h"
#include "simdjson/rvv-vls/bitmanipulation.h"
#include "simdjson/internal/simdprune_tables.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
namespace rvv_vls {
namespace {
namespace simd {
#if __riscv_v_fixed_vlen >= 512
static constexpr size_t VL8 = 512/8;
using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(512)));
using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512)));
using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8)));
using vbitmask_t = uint64_t;
#else
static constexpr size_t VL8 = __riscv_v_fixed_vlen/8;
using vint8_t = vint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
using vuint8_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
using vbool_t = vbool8_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen/8)));
#if __riscv_v_fixed_vlen == 128
using vbitmask_t = uint16_t;
#elif __riscv_v_fixed_vlen == 256
using vbitmask_t = uint32_t;
#endif
#endif
#if __riscv_v_fixed_vlen == 128
using vuint8x64_t = vuint8m4_t __attribute__((riscv_rvv_vector_bits(512)));
using vboolx64_t = vbool2_t __attribute__((riscv_rvv_vector_bits(512/8)));
#elif __riscv_v_fixed_vlen == 256
using vuint8x64_t = vuint8m2_t __attribute__((riscv_rvv_vector_bits(512)));
using vboolx64_t = vbool4_t __attribute__((riscv_rvv_vector_bits(512/8)));
#else
using vuint8x64_t = vuint8m1_t __attribute__((riscv_rvv_vector_bits(512)));
using vboolx64_t = vbool8_t __attribute__((riscv_rvv_vector_bits(512/8)));
#endif
template<typename T>
struct simd8;
// SIMD byte mask type (returned by things like eq and gt)
template<>
struct simd8<bool> {
vbool_t value;
using bitmask_t = vbitmask_t;
static constexpr int SIZE = sizeof(value);
simdjson_inline simd8(const vbool_t _value) : value(_value) {}
simdjson_inline simd8() : simd8(__riscv_vmclr_m_b8(VL8)) {}
simdjson_inline simd8(bool _value) : simd8(splat(_value)) {}
simdjson_inline operator const vbool_t&() const { return value; }
simdjson_inline operator vbool_t&() { return value; }
static simdjson_inline simd8<bool> splat(bool _value) {
return __riscv_vreinterpret_b8(__riscv_vmv_v_x_u64m1(((uint64_t)!_value)-1, 1));
}
simdjson_inline vbitmask_t to_bitmask() const {
#if __riscv_v_fixed_vlen == 128
return __riscv_vmv_x(__riscv_vreinterpret_u16m1(value));
#elif __riscv_v_fixed_vlen == 256
return __riscv_vmv_x(__riscv_vreinterpret_u32m1(value));
#else
return __riscv_vmv_x(__riscv_vreinterpret_u64m1(value));
#endif
}
// Bit operations
simdjson_inline simd8<bool> operator|(const simd8<bool> other) const { return __riscv_vmor(*this, other, VL8); }
simdjson_inline simd8<bool> operator&(const simd8<bool> other) const { return __riscv_vmand(*this, other, VL8); }
simdjson_inline simd8<bool> operator^(const simd8<bool> other) const { return __riscv_vmxor(*this, other, VL8); }
simdjson_inline simd8<bool> bit_andnot(const simd8<bool> other) const { return __riscv_vmandn(other, *this, VL8); }
simdjson_inline simd8<bool> operator~() const { return __riscv_vmnot(*this, VL8); }
simdjson_inline simd8<bool>& operator|=(const simd8<bool> other) { auto this_cast = static_cast<simd8<bool>*>(this); *this_cast = *this_cast | other; return *this_cast; }
simdjson_inline simd8<bool>& operator&=(const simd8<bool> other) { auto this_cast = static_cast<simd8<bool>*>(this); *this_cast = *this_cast & other; return *this_cast; }
simdjson_inline simd8<bool>& operator^=(const simd8<bool> other) { auto this_cast = static_cast<simd8<bool>*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
};
// Unsigned bytes
template<>
struct simd8<uint8_t> {
vuint8_t value;
static constexpr int SIZE = sizeof(value);
simdjson_inline simd8(const vuint8_t _value) : value(_value) {}
simdjson_inline simd8() : simd8(zero()) {}
simdjson_inline simd8(const uint8_t values[VL8]) : simd8(load(values)) {}
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
simdjson_inline simd8(simd8<bool> mask) : value(__riscv_vmerge_vxm_u8m1(zero(), -1, (vbool_t)mask, VL8)) {}
simdjson_inline operator const vuint8_t&() const { return this->value; }
simdjson_inline operator vuint8_t&() { return this->value; }
simdjson_inline simd8(
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
) : simd8(vuint8_t{
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15
}) {}
// Repeat 16 values as many times as necessary (usually for lookup tables)
simdjson_inline static simd8<uint8_t> repeat_16(
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
) {
return simd8<uint8_t>(
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15
);
}
static simdjson_inline vuint8_t splat(uint8_t _value) { return __riscv_vmv_v_x_u8m1(_value, VL8); }
static simdjson_inline vuint8_t zero() { return splat(0); }
static simdjson_inline vuint8_t load(const uint8_t values[VL8]) { return __riscv_vle8_v_u8m1(values, VL8); }
// Bit operations
simdjson_inline simd8<uint8_t> operator|(const simd8<uint8_t> other) const { return __riscv_vor_vv_u8m1( value, other, VL8); }
simdjson_inline simd8<uint8_t> operator&(const simd8<uint8_t> other) const { return __riscv_vand_vv_u8m1( value, other, VL8); }
simdjson_inline simd8<uint8_t> operator^(const simd8<uint8_t> other) const { return __riscv_vxor_vv_u8m1( value, other, VL8); }
simdjson_inline simd8<uint8_t> operator~() const { return __riscv_vnot_v_u8m1(value, VL8); }
#if __riscv_zvbb
simdjson_inline simd8<uint8_t> bit_andnot(const simd8<uint8_t> other) const { return __riscv_vandn_vv_u8m1(other, value, VL8); }
#else
simdjson_inline simd8<uint8_t> bit_andnot(const simd8<uint8_t> other) const { return other & ~*this; }
#endif
simdjson_inline simd8<uint8_t>& operator|=(const simd8<uint8_t> other) { value = *this | other; return *this; }
simdjson_inline simd8<uint8_t>& operator&=(const simd8<uint8_t> other) { value = *this & other; return *this; }
simdjson_inline simd8<uint8_t>& operator^=(const simd8<uint8_t> other) { value = *this ^ other; return *this; }
simdjson_inline simd8<bool> operator==(const simd8<uint8_t> other) const { return __riscv_vmseq(value, other, VL8); }
simdjson_inline simd8<bool> operator==(uint8_t other) const { return __riscv_vmseq(value, other, VL8); }
template<int N=1>
simdjson_inline simd8<uint8_t> prev(const simd8<uint8_t> prev_chunk) const {
return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8);
}
// Store to array
simdjson_inline void store(uint8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); }
// Saturated math
simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return __riscv_vsaddu(value, other, VL8); }
simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return __riscv_vssubu(value, other, VL8); }
// Addition/subtraction are the same for signed and unsigned
simdjson_inline simd8<uint8_t> operator+(const simd8<uint8_t> other) const { return __riscv_vadd(value, other, VL8); }
simdjson_inline simd8<uint8_t> operator-(const simd8<uint8_t> other) const { return __riscv_vsub(value, other, VL8); }
simdjson_inline simd8<uint8_t>& operator+=(const simd8<uint8_t> other) { value = *this + other; return *this; }
simdjson_inline simd8<uint8_t>& operator-=(const simd8<uint8_t> other) { value = *this - other; return *this; }
// Order-specific operations
simdjson_inline simd8<bool> operator<=(const simd8<uint8_t> other) const { return __riscv_vmsleu(value, other, VL8); }
simdjson_inline simd8<bool> operator>=(const simd8<uint8_t> other) const { return __riscv_vmsgeu(value, other, VL8); }
simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return __riscv_vmsltu(value, other, VL8); }
simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return __riscv_vmsgtu(value, other, VL8); }
// Same as >, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero.
simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return simd8<uint8_t>(*this > other); }
// Same as <, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero.
simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return simd8<uint8_t>(*this < other); }
// Bit-specific operations
simdjson_inline bool any_bits_set_anywhere() const {
return __riscv_vfirst(__riscv_vmsne(value, 0, VL8), VL8) >= 0;
}
simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return (*this & bits).any_bits_set_anywhere(); }
template<int N>
simdjson_inline simd8<uint8_t> shr() const { return __riscv_vsrl(value, N, VL8); }
template<int N>
simdjson_inline simd8<uint8_t> shl() const { return __riscv_vsll(value, N, VL8); }
// Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
template<typename L>
simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
return __riscv_vrgather(lookup_table, value, VL8);
}
// compress inactive elements, to match AVX-512 behavior
template<typename L>
simdjson_inline void compress(vbitmask_t mask, L * output) const {
mask = (vbitmask_t)~mask;
#if __riscv_v_fixed_vlen == 128
vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u16m1(mask, 1));
#elif __riscv_v_fixed_vlen == 256
vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u32m1(mask, 1));
#else
vbool8_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1));
#endif
__riscv_vse8_v_u8m1(output, __riscv_vcompress(value, m, VL8), count_ones(mask));
}
template<typename L>
simdjson_inline simd8<L> lookup_16(
L replace0, L replace1, L replace2, L replace3,
L replace4, L replace5, L replace6, L replace7,
L replace8, L replace9, L replace10, L replace11,
L replace12, L replace13, L replace14, L replace15) const {
return lookup_16(simd8<L>::repeat_16(
replace0, replace1, replace2, replace3,
replace4, replace5, replace6, replace7,
replace8, replace9, replace10, replace11,
replace12, replace13, replace14, replace15
));
}
};
// Signed bytes
template<>
struct simd8<int8_t> {
vint8_t value;
static constexpr int SIZE = sizeof(value);
simdjson_inline simd8(const vint8_t _value) : value(_value) {}
simdjson_inline simd8() : simd8(zero()) {}
simdjson_inline simd8(const int8_t values[VL8]) : simd8(load(values)) {}
simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
simdjson_inline operator const vint8_t&() const { return this->value; }
simdjson_inline operator vint8_t&() { return this->value; }
simdjson_inline simd8(
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
) : simd8(vint8_t{
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15
}) {}
// Repeat 16 values as many times as necessary (usually for lookup tables)
simdjson_inline static simd8<int8_t> repeat_16(
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
) {
return simd8<int8_t>(
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15
);
}
static simdjson_inline vint8_t splat(int8_t _value) { return __riscv_vmv_v_x_i8m1(_value, VL8); }
static simdjson_inline vint8_t zero() { return splat(0); }
static simdjson_inline vint8_t load(const int8_t values[VL8]) { return __riscv_vle8_v_i8m1(values, VL8); }
simdjson_inline void store(int8_t dst[VL8]) const { return __riscv_vse8(dst, value, VL8); }
// Explicit conversion to/from unsigned
simdjson_inline explicit simd8(const vuint8_t other): simd8(__riscv_vreinterpret_i8m1(other)) {}
simdjson_inline explicit operator simd8<uint8_t>() const { return __riscv_vreinterpret_u8m1(value); }
// Math
simdjson_inline simd8<int8_t> operator+(const simd8<int8_t> other) const { return __riscv_vadd(value, other, VL8); }
simdjson_inline simd8<int8_t> operator-(const simd8<int8_t> other) const { return __riscv_vsub(value, other, VL8); }
simdjson_inline simd8<int8_t>& operator+=(const simd8<int8_t> other) { value = *this + other; return *this; }
simdjson_inline simd8<int8_t>& operator-=(const simd8<int8_t> other) { value = *this - other; return *this; }
// Order-sensitive comparisons
simdjson_inline simd8<int8_t> max_val( const simd8<int8_t> other) const { return __riscv_vmax( value, other, VL8); }
simdjson_inline simd8<int8_t> min_val( const simd8<int8_t> other) const { return __riscv_vmin( value, other, VL8); }
simdjson_inline simd8<bool> operator>( const simd8<int8_t> other) const { return __riscv_vmsgt(value, other, VL8); }
simdjson_inline simd8<bool> operator<( const simd8<int8_t> other) const { return __riscv_vmslt(value, other, VL8); }
simdjson_inline simd8<bool> operator==(const simd8<int8_t> other) const { return __riscv_vmseq(value, other, VL8); }
template<int N=1>
simdjson_inline simd8<int8_t> prev(const simd8<int8_t> prev_chunk) const {
return __riscv_vslideup(__riscv_vslidedown(prev_chunk, VL8-N, VL8), value, N, VL8);
}
// Perform a lookup assuming no value is larger than 16
template<typename L>
simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
return __riscv_vrgather(lookup_table, value, VL8);
}
template<typename L>
simdjson_inline simd8<L> lookup_16(
L replace0, L replace1, L replace2, L replace3,
L replace4, L replace5, L replace6, L replace7,
L replace8, L replace9, L replace10, L replace11,
L replace12, L replace13, L replace14, L replace15) const {
return lookup_16(simd8<L>::repeat_16(
replace0, replace1, replace2, replace3,
replace4, replace5, replace6, replace7,
replace8, replace9, replace10, replace11,
replace12, replace13, replace14, replace15
));
}
};
template<typename T>
struct simd8x64;
template<>
struct simd8x64<uint8_t> {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<uint8_t>);
vuint8x64_t value;
#if __riscv_v_fixed_vlen >= 512
template<int idx> simd8<uint8_t> get() const { return value; }
#else
template<int idx> simd8<uint8_t> get() const { return __riscv_vget_u8m1(value, idx); }
#endif
simdjson_inline operator const vuint8x64_t&() const { return this->value; }
simdjson_inline operator vuint8x64_t&() { return this->value; }
simd8x64(const simd8x64<uint8_t>& o) = delete; // no copy allowed
simd8x64<uint8_t>& operator=(const simd8<uint8_t>& other) = delete; // no assignment allowed
simd8x64() = delete; // no default constructor allowed
#if __riscv_v_fixed_vlen == 128
simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m4(ptr, n)) {}
#elif __riscv_v_fixed_vlen == 256
simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m2(ptr, n)) {}
#else
simdjson_inline simd8x64(const uint8_t *ptr, size_t n = 64) : value(__riscv_vle8_v_u8m1(ptr, n)) {}
#endif
simdjson_inline void store(uint8_t ptr[64]) const {
__riscv_vse8(ptr, value, 64);
}
simdjson_inline bool is_ascii() const {
#if __riscv_v_fixed_vlen == 128
return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m4(value), 0, 64), 64) < 0;
#elif __riscv_v_fixed_vlen == 256
return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m2(value), 0, 64), 64) < 0;
#else
return __riscv_vfirst(__riscv_vmslt(__riscv_vreinterpret_i8m1(value), 0, 64), 64) < 0;
#endif
}
// compress inactive elements, to match AVX-512 behavior
simdjson_inline uint64_t compress(uint64_t mask, uint8_t * output) const {
mask = ~mask;
#if __riscv_v_fixed_vlen == 128
vboolx64_t m = __riscv_vreinterpret_b2(__riscv_vmv_s_x_u64m1(mask, 1));
#elif __riscv_v_fixed_vlen == 256
vboolx64_t m = __riscv_vreinterpret_b4(__riscv_vmv_s_x_u64m1(mask, 1));
#else
vboolx64_t m = __riscv_vreinterpret_b8(__riscv_vmv_s_x_u64m1(mask, 1));
#endif
size_t cnt = count_ones(mask);
__riscv_vse8(output, __riscv_vcompress(value, m, 64), cnt);
return cnt;
}
simdjson_inline uint64_t eq(const uint8_t m) const {
return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmseq(value, m, 64)));
}
simdjson_inline uint64_t lteq(const uint8_t m) const {
return __riscv_vmv_x(__riscv_vreinterpret_u64m1(__riscv_vmsleu(value, m, 64)));
}
}; // struct simd8x64<uint8_t>
} // namespace simd
} // unnamed namespace
} // namespace rvv_vls
} // namespace simdjson
#endif // SIMDJSON_RVV_VLS_SIMD_H
@@ -1,58 +0,0 @@
#ifndef SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H
#define SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/rvv-vls/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
namespace rvv_vls {
namespace {
using namespace simd;
// Holds backslashes and quotes locations.
struct backslash_and_quote {
public:
static constexpr uint64_t BYTES_PROCESSED = sizeof(simd8<uint8_t>);
simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
simdjson_inline bool has_backslash() { return ((quote_bits - 1) & bs_bits) != 0; }
simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
uint64_t bs_bits;
uint64_t quote_bits;
}; // struct backslash_and_quote
simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
simd8<uint8_t> v(src);
v.store(dst);
return { (v == '\\').to_bitmask(), (v == '"').to_bitmask() };
}
struct escaping {
static constexpr uint64_t BYTES_PROCESSED = sizeof(simd8<uint8_t>);
simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst);
simdjson_inline bool has_escape() { return escape_bits != 0; }
simdjson_inline int escape_index() { return trailing_zeroes(escape_bits) / 4; }
uint64_t escape_bits;
}; // struct escaping
simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) {
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "escaping finder must process fewer than SIMDJSON_PADDING bytes");
simd8<uint8_t> v(src);
v.store(dst);
return { ((v == '"') | (v == '\\') | (v == 32)).to_bitmask() };
}
} // unnamed namespace
} // namespace rvv_vls
} // namespace simdjson
#endif // SIMDJSON_RVV_VLS_STRINGPARSING_DEFS_H
-1
View File
@@ -265,7 +265,6 @@ namespace simd {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
static_assert(NUM_CHUNKS == 4, "Westmere kernel should use four registers per 64-byte block.");
const simd8<T> chunks[NUM_CHUNKS];
template<int idx> simd8<uint8_t> get() const { return idx < NUM_CHUNKS ? chunks[idx] : simd8<T>(); }
simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
@@ -14,6 +14,7 @@ using namespace simd;
struct backslash_and_quote {
public:
static constexpr uint32_t BYTES_PROCESSED = 32;
// We only copy if dst is non-null.
simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
@@ -31,8 +32,10 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
simd8<uint8_t> v0(src);
simd8<uint8_t> v1(src + 16);
v0.store(dst);
v1.store(dst + 16);
if(dst != nullptr) {
v0.store(dst);
v1.store(dst + 16);
}
uint64_t bs_and_quote = simd8x64<bool>(v0 == '\\', v1 == '\\', v0 == '"', v1 == '"').to_bitmask();
return {
uint32_t(bs_and_quote), // bs_bits
+1 -1
View File
@@ -108,7 +108,7 @@ else:
RelativeRoot = str # Literal['src','include'] # Literal not supported in Python 3.7 (CI)
RELATIVE_ROOTS: List[RelativeRoot] = ['src', 'include' ]
Implementation = str # Literal['arm64', 'fallback', 'haswell', 'icelake', 'ppc64', 'westmere', 'lsx', 'lasx'] # Literal not supported in Python 3.7 (CI)
IMPLEMENTATIONS: List[Implementation] = [ 'arm64', 'haswell', 'icelake', 'lasx', 'lsx', 'ppc64', 'rvv-vls', 'westmere', 'fallback' ]
IMPLEMENTATIONS: List[Implementation] = [ 'arm64', 'haswell', 'icelake', 'lasx', 'lsx', 'ppc64', 'westmere', 'fallback' ]
GENERIC_INCLUDE = "simdjson/generic"
GENERIC_SRC = "generic"
BUILTIN = "simdjson/builtin"
+4
View File
@@ -150,6 +150,10 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
simdjson_warn_unused std::pair<const uint8_t *, bool> dom_parser_implementation::parse_string_if_needed(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return arm64::stringparsing::parse_string_if_needed(src, dst, allow_replacement);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return arm64::stringparsing::parse_string(src, dst, allow_replacement);
+4
View File
@@ -444,6 +444,10 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
simdjson_warn_unused std::pair<const uint8_t *, bool> dom_parser_implementation::parse_string_if_needed(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return fallback::stringparsing::parse_string_if_needed(src, dst, allow_replacement);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return fallback::stringparsing::parse_string(src, dst, replacement_char);
+1 -1
View File
@@ -18,4 +18,4 @@ simdjson_inline bool is_ascii(const simd8x64<uint8_t>& input);
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#endif // SIMDJSON_SRC_GENERIC_DOM_PARSER_IMPLEMENTATION_H
#endif // SIMDJSON_SRC_GENERIC_DOM_PARSER_IMPLEMENTATION_H
+11 -11
View File
@@ -119,7 +119,7 @@ using namespace simd;
simdjson_inline simd8<uint8_t> is_incomplete(const simd8<uint8_t> input) {
// If the previous input's last 3 bytes match this, they're too short (they ended at EOF):
// ... 1111____ 111_____ 11______
#if SIMDJSON_IMPLEMENTATION_ICELAKE || (SIMDJSON_IMPLEMENTATION_RVV_VLS && __riscv_v_fixed_vlen >= 512)
#if SIMDJSON_IMPLEMENTATION_ICELAKE
static const uint8_t max_array[64] = {
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
@@ -180,18 +180,18 @@ using namespace simd;
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block.");
SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 1) {
this->check_utf8_bytes(input.get<0>(), this->prev_input_block);
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 2) {
this->check_utf8_bytes(input.get<0>(), this->prev_input_block);
this->check_utf8_bytes(input.get<1>(), input.get<0>());
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 4) {
this->check_utf8_bytes(input.get<0>(), this->prev_input_block);
this->check_utf8_bytes(input.get<1>(), input.get<0>());
this->check_utf8_bytes(input.get<2>(), input.get<1>());
this->check_utf8_bytes(input.get<3>(), input.get<2>());
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
this->check_utf8_bytes(input.chunks[3], input.chunks[2]);
}
this->prev_incomplete = is_incomplete(input.get<simd8x64<uint8_t>::NUM_CHUNKS-1>());
this->prev_input_block = input.get<simd8x64<uint8_t>::NUM_CHUNKS-1>();
this->prev_incomplete = is_incomplete(input.chunks[simd8x64<uint8_t>::NUM_CHUNKS-1]);
this->prev_input_block = input.chunks[simd8x64<uint8_t>::NUM_CHUNKS-1];
}
}
// do not forget to call check_eof!
@@ -206,4 +206,4 @@ using namespace simd;
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#endif // SIMDJSON_SRC_GENERIC_STAGE1_UTF8_LOOKUP4_ALGORITHM_H
#endif // SIMDJSON_SRC_GENERIC_STAGE1_UTF8_LOOKUP4_ALGORITHM_H
+89 -1
View File
@@ -1,4 +1,5 @@
#include <cstdint>
#include <cstdio>
#include <cstring>
#ifndef SIMDJSON_SRC_GENERIC_STAGE2_STRINGPARSING_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
@@ -139,6 +140,93 @@ simdjson_inline bool handle_unicode_codepoint_wobbly(const uint8_t **src_ptr,
return offset > 0;
}
/**
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote.
* If there is no need for unescaping, it avoids copying the string.
* There
* must be an unescaped quote terminating the string. It returns the final output
* position as pointer. In case of error (e.g., the string has bad escaped codes),
* then null_ptr is returned. It is assumed that the output buffer is large
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
* SIMDJSON_PADDING bytes.
*/
simdjson_warn_unused simdjson_inline std::pair<const uint8_t *,bool> parse_string_if_needed(const uint8_t *src, uint8_t *dst, bool allow_replacement) {
const uint8_t *srcinit = src;
while (1) {
// Find the backslash and quote in them, we pass null because we do not copy.
auto bs_quote = backslash_and_quote::copy_and_find(src, nullptr);
// If the next thing is the end quote, copy and return
if (bs_quote.has_quote_first()) {
// we encountered quotes first.
return {src + bs_quote.quote_index(), false};
}
if (bs_quote.has_backslash()) {
std::memcpy(dst, srcinit, src - srcinit + backslash_and_quote::BYTES_PROCESSED);
dst += src - srcinit;
auto bs_dist = bs_quote.backslash_index();
uint8_t escape_char = src[bs_dist + 1];
if (escape_char == 'u') {
src += bs_dist;
dst += bs_dist;
if (!handle_unicode_codepoint(&src, &dst, allow_replacement)) {
return {nullptr, true};
}
} else {
uint8_t escape_result = escape_map[escape_char];
if (escape_result == 0u) {
return {nullptr, true};
}
dst[bs_dist] = escape_result;
src += bs_dist + 2;
dst += bs_dist + 1;
}
break;
} else {
src += backslash_and_quote::BYTES_PROCESSED;
}
}
while (1) {
// Copy the next n bytes, and find the backslash and quote in them.
auto bs_quote = backslash_and_quote::copy_and_find(src, dst);
// If the next thing is the end quote, copy and return
if (bs_quote.has_quote_first()) {
// we encountered quotes first. Move dst to point to quotes and exit
return {dst + bs_quote.quote_index(), true};
}
if (bs_quote.has_backslash()) {
/* find out where the backspace is */
auto bs_dist = bs_quote.backslash_index();
uint8_t escape_char = src[bs_dist + 1];
/* we encountered backslash first. Handle backslash */
if (escape_char == 'u') {
/* move src/dst up to the start; they will be further adjusted
within the unicode codepoint handling code. */
src += bs_dist;
dst += bs_dist;
if (!handle_unicode_codepoint(&src, &dst, allow_replacement)) {
return {nullptr, true};
}
} else {
/* simple 1:1 conversion. Will eat bs_dist+2 characters in input and
* write bs_dist+1 characters to output
* note this may reach beyond the part of the buffer we've actually
* seen. I think this is ok */
uint8_t escape_result = escape_map[escape_char];
if (escape_result == 0u) {
return {nullptr, true}; /* bogus escape value is an error */
}
dst[bs_dist] = escape_result;
src += bs_dist + 2;
dst += bs_dist + 1;
}
} else {
/* they are the same. Since they can't co-occur, it means we
* encountered neither. */
src += backslash_and_quote::BYTES_PROCESSED;
dst += backslash_and_quote::BYTES_PROCESSED;
}
}
}
/**
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
+4
View File
@@ -147,6 +147,10 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
simdjson_warn_unused std::pair<const uint8_t *, bool> dom_parser_implementation::parse_string_if_needed(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return haswell::stringparsing::parse_string_if_needed(src, dst, allow_replacement);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return haswell::stringparsing::parse_string(src, dst, replacement_char);
+4
View File
@@ -193,6 +193,10 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
simdjson_warn_unused std::pair<const uint8_t *, bool> dom_parser_implementation::parse_string_if_needed(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return icelake::stringparsing::parse_string_if_needed(src, dst, allow_replacement);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return icelake::stringparsing::parse_string(src, dst, replacement_char);
+1 -18
View File
@@ -118,17 +118,6 @@ static const simdjson::lsx::implementation* get_lsx_singleton() {
} // namespace simdjson
#endif // SIMDJSON_IMPLEMENTATION_LSX
#if SIMDJSON_IMPLEMENTATION_RVV_VLS
#include <simdjson/rvv-vls/implementation.h>
namespace simdjson {
namespace internal {
static const simdjson::rvv_vls::implementation* get_rvv_vls_singleton() {
static const simdjson::rvv_vls::implementation rvv_vls_singleton{};
return &rvv_vls_singleton;
}
} // namespace internal
} // namespace simdjson
#endif // SIMDJSON_IMPLEMENTATION_RVV_VLS
#undef SIMDJSON_CONDITIONAL_INCLUDE
@@ -142,7 +131,7 @@ namespace internal {
+ SIMDJSON_IMPLEMENTATION_HASWELL + SIMDJSON_IMPLEMENTATION_WESTMERE \
+ SIMDJSON_IMPLEMENTATION_ARM64 + SIMDJSON_IMPLEMENTATION_PPC64 \
+ SIMDJSON_IMPLEMENTATION_LSX + SIMDJSON_IMPLEMENTATION_LASX \
+ SIMDJSON_IMPLEMENTATION_RVV_VLS + SIMDJSON_IMPLEMENTATION_FALLBACK == 1)
+ SIMDJSON_IMPLEMENTATION_FALLBACK == 1)
#if SIMDJSON_SINGLE_IMPLEMENTATION
static const implementation* get_single_implementation() {
@@ -168,9 +157,6 @@ namespace internal {
#if SIMDJSON_IMPLEMENTATION_LASX
get_lasx_singleton();
#endif
#if SIMDJSON_IMPLEMENTATION_RVV_VLS
get_rvv_vls_singleton();
#endif
#if SIMDJSON_IMPLEMENTATION_FALLBACK
get_fallback_singleton();
#endif
@@ -231,9 +217,6 @@ static const std::initializer_list<const implementation *>& get_available_implem
#if SIMDJSON_IMPLEMENTATION_LSX
get_lsx_singleton(),
#endif
#if SIMDJSON_IMPLEMENTATION_RVV_VLS
get_rvv_vls_singleton(),
#endif
#if SIMDJSON_IMPLEMENTATION_FALLBACK
get_fallback_singleton(),
#endif
-10
View File
@@ -239,16 +239,6 @@ static inline uint32_t detect_supported_architectures() {
return host_isa;
}
#elif SIMDJSON_IS_RISCV64
static inline uint32_t detect_supported_architectures() {
uint32_t host_isa = instruction_set::DEFAULT;
#if SIMDJSON_IS_RVV_VLS
host_isa |= instruction_set::RVV_VLS;
#endif
return host_isa;
}
#else // fallback
+4
View File
@@ -110,6 +110,10 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
simdjson_warn_unused std::pair<const uint8_t *, bool> dom_parser_implementation::parse_string_if_needed(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return lasx::stringparsing::parse_string_if_needed(src, dst, allow_replacement);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return lasx::stringparsing::parse_string(src, dst, allow_replacement);
+4
View File
@@ -114,6 +114,10 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
simdjson_warn_unused std::pair<const uint8_t *, bool> dom_parser_implementation::parse_string_if_needed(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return lsx::stringparsing::parse_string_if_needed(src, dst, allow_replacement);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return lsx::stringparsing::parse_string(src, dst, allow_replacement);
+4
View File
@@ -120,6 +120,10 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
simdjson_warn_unused std::pair<const uint8_t *, bool> dom_parser_implementation::parse_string_if_needed(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return ppc64::stringparsing::parse_string_if_needed(src, dst, allow_replacement);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return ppc64::stringparsing::parse_string(src, dst, replacement_char);
-132
View File
@@ -1,132 +0,0 @@
#ifndef SIMDJSON_SRC_RVV_VLS_CPP
#define SIMDJSON_SRC_RVV_VLS_CPP
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include <base.h>
#endif // SIMDJSON_CONDITIONAL_INCLUDE
#include <simdjson/rvv-vls.h>
#include <simdjson/rvv-vls/implementation.h>
#include <simdjson/rvv-vls/begin.h>
#include <simdjson/rvv-vls/simd.h>
#include <generic/amalgamated.h>
#include <generic/stage1/amalgamated.h>
#include <generic/stage2/amalgamated.h>
//
// Stage 1
//
namespace simdjson {
namespace rvv_vls {
simdjson_warn_unused error_code implementation::create_dom_parser_implementation(
size_t capacity,
size_t max_depth,
std::unique_ptr<internal::dom_parser_implementation>& dst
) const noexcept {
dst.reset( new (std::nothrow) dom_parser_implementation() );
if (!dst) { return MEMALLOC; }
if (auto err = dst->set_capacity(capacity))
return err;
if (auto err = dst->set_max_depth(max_depth))
return err;
return SUCCESS;
}
namespace {
using namespace simd;
simdjson_inline json_character_block json_character_block::classify(const simd::simd8x64<uint8_t>& in) {
static const uint8_t wsTable[16] = { ' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100 };
static const uint8_t opTable[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', '{', ',', '}', 0, 0 };
vuint8_t vws = __riscv_vle8_v_u8m1(wsTable, 16);
vuint8_t vop = __riscv_vle8_v_u8m1(opTable, 16);
vuint8x64_t lo = __riscv_vand(in, 15, 64);
vuint8x64_t curl = __riscv_vor(in, 0x20, 64);
#if __riscv_v_fixed_vlen == 128
vboolx64_t mws = __riscv_vmseq(simdutf_vrgather_u8m1x4(vws, lo), in, 64);
vboolx64_t mop = __riscv_vmseq(simdutf_vrgather_u8m1x4(vop, lo), curl, 64);
#elif __riscv_v_fixed_vlen == 256
vboolx64_t mws = __riscv_vmseq(simdutf_vrgather_u8m1x2(vws, lo), in, 64);
vboolx64_t mop = __riscv_vmseq(simdutf_vrgather_u8m1x2(vop, lo), curl, 64);
#else
vboolx64_t mws = __riscv_vmseq(__riscv_vrgather(vws, lo, 64), in, 64);
vboolx64_t mop = __riscv_vmseq(__riscv_vrgather(vop, lo, 64), curl, 64);
#endif
return {
__riscv_vmv_x(__riscv_vreinterpret_u64m1(mws)),
__riscv_vmv_x(__riscv_vreinterpret_u64m1(mop))
};
}
simdjson_inline bool is_ascii(const simd8x64<uint8_t>& input) {
return input.is_ascii();
}
simdjson_inline simd8<uint8_t> must_be_2_3_continuation(const simd8<uint8_t> prev2, const simd8<uint8_t> prev3) {
simd8<uint8_t> is_third_byte = prev2.saturating_sub(0xe0u-0x80); // Only 111_____ will be >= 0x80
simd8<uint8_t> is_fourth_byte = prev3.saturating_sub(0xf0u-0x80); // Only 1111____ will be >= 0x80
return is_third_byte | is_fourth_byte;
}
} // unnamed namespace
} // namespace rvv_vls
} // namespace simdjson
//
// Stage 2
//
//
// Implementation-specific overrides
//
namespace simdjson {
namespace rvv_vls {
simdjson_warn_unused error_code implementation::minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept {
return rvv_vls::stage1::json_minifier::minify<64>(buf, len, dst, dst_len);
}
simdjson_warn_unused error_code dom_parser_implementation::stage1(const uint8_t *_buf, size_t _len, stage1_mode streaming) noexcept {
this->buf = _buf;
this->len = _len;
return rvv_vls::stage1::json_structural_indexer::index<64>(buf, len, *this, streaming);
}
simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t len) const noexcept {
return rvv_vls::stage1::generic_validate_utf8(buf,len);
}
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
return stage2::tape_builder::parse_document<false>(*this, _doc);
}
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return rvv_vls::stringparsing::parse_string(src, dst, allow_replacement);
}
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_wobbly_string(const uint8_t *src, uint8_t *dst) const noexcept {
return rvv_vls::stringparsing::parse_wobbly_string(src, dst);
}
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
auto error = stage1(_buf, _len, stage1_mode::regular);
if (error) { return error; }
return stage2(_doc);
}
} // namespace rvv_vls
} // namespace simdjson
#include <simdjson/rvv-vls/end.h>
#endif // SIMDJSON_SRC_RVV_VLS_CPP
-3
View File
@@ -41,9 +41,6 @@ SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS
#if SIMDJSON_IMPLEMENTATION_LSX
#include <lsx.cpp>
#endif
#if SIMDJSON_IMPLEMENTATION_RVV_VLS
#include <rvv-vls.cpp>
#endif
#if SIMDJSON_IMPLEMENTATION_FALLBACK
#include <fallback.cpp>
#endif
+5 -1
View File
@@ -152,7 +152,11 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
return stage2::tape_builder::parse_document<true>(*this, _doc);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused std::pair<const uint8_t *, bool> dom_parser_implementation::parse_string_if_needed(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
return westmere::stringparsing::parse_string_if_needed(src, dst, allow_replacement);
}
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
return westmere::stringparsing::parse_string(src, dst, replacement_char);
}
+1 -1
View File
@@ -79,7 +79,7 @@ if (BASH AND (NOT WIN32) AND SIMDJSON_BASH AND (TARGET json2json)) # The scripts
$<TARGET_FILE:checkimplementation>
)
endif()
if((CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL x86_64 OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL amd64) AND NOT DEFINED CMAKE_CROSSCOMPILING_EMULATOR)
if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL x86_64 OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL amd64)
add_test(
NAME simdjson_force_implementation_error
COMMAND