Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ option(BUILD_UNITTEST "Build unittest." ON)
option(BUILD_FUZZ "Build fuzz." OFF)
option(BUILD_BENCH "Build benchmark." OFF)
option(ENABLE_SVE2_128 "Build for Arm SVE2 with 128 bit vector size" OFF)
option(ENABLE_RVV_128 "Build for RISC-V RVV with 128 bit vector size" OFF)

set(CMAKE_CXX_EXTENSIONS OFF)
if(BUILD_UNITTEST)
Expand Down
4 changes: 4 additions & 0 deletions cmake/set_arch_flags.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ function(set_arch_flags target arch)
else()
target_compile_options(${target} PRIVATE -march=armv8-a)
endif()
elseif(arch MATCHES "riscv64")
if(ENABLE_RVV_128)
target_compile_options(${target} PRIVATE -march=rv64gcv_zvl128b -mrvv-vector-bits=zvl)
endif()
else()
message(FATAL_ERROR "Unsupported architecture: ${arch}")
endif()
Expand Down
70 changes: 70 additions & 0 deletions include/sonic/internal/arch/common/riscv_common/base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2022 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once
#include <sonic/macro.h>

#include <cstring>

namespace sonic_json {
namespace internal {
namespace riscv_common {

// 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.

sonic_force_inline int TrailingZeroes(uint64_t input_num) {
////////
// You might expect the next line to be equivalent to
// return (int)_tzcnt_u64(input_num);
// but the generated code differs and might be less efficient?
////////
return __builtin_ctzll(input_num);
}

/* result might be undefined when input_num is zero */
sonic_force_inline uint64_t ClearLowestBit(uint64_t input_num) {
return input_num & (input_num - 1);
}

/* result might be undefined when input_num is zero */
sonic_force_inline int LeadingZeroes(uint64_t input_num) {
return __builtin_clzll(input_num);
}

sonic_force_inline long long int CountOnes(uint64_t input_num) {
return __builtin_popcountll(input_num);
}

sonic_force_inline uint64_t PrefixXor(uint64_t bitmask) {
bitmask ^= bitmask << 1;
bitmask ^= bitmask << 2;
bitmask ^= bitmask << 4;
bitmask ^= bitmask << 8;
bitmask ^= bitmask << 16;
bitmask ^= bitmask << 32;
return bitmask;
}

template <size_t ChunkSize>
sonic_force_inline void Xmemcpy(void* dst_, const void* src_, size_t chunks) {
std::memcpy(dst_, src_, chunks * ChunkSize);
}

} // namespace riscv_common
} // namespace internal
} // namespace sonic_json
160 changes: 160 additions & 0 deletions include/sonic/internal/arch/common/riscv_common/skip.inc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* Copyright 2022 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef VEC_LEN
#error "Define vector length firstly!"
#endif

// pos is the after the ending quote
sonic_force_inline int SkipString(const uint8_t *data, size_t &pos,
size_t len) {
const static int kEscaped = 2;
const static int kNormal = 1;
const static int kUnclosed = 0;
uint16_t quote_bits = 0;
uint16_t bs_bits = 0;
int ret = kNormal;
while (pos + VEC_LEN <= len) {
vuint8m1_t v = __riscv_vle8_v_u8m1(data + pos, 16);
bs_bits = to_bitmask(
__riscv_vmseq_vv_u8m1_b8(v, __riscv_vmv_v_x_u8m1('\\', 16), 16));
quote_bits = to_bitmask(
__riscv_vmseq_vv_u8m1_b8(v, __riscv_vmv_v_x_u8m1('"', 16), 16));
if (((bs_bits - 1) & quote_bits) != 0) {
pos += TrailingZeroes(quote_bits) + 1;
return ret;
}
if (bs_bits) {
ret = kEscaped;
pos += (TrailingZeroes(bs_bits) + 2);
while (pos < len) {
if (data[pos] == '\\') {
pos += 2;
} else {
break;
}
}
} else {
pos += VEC_LEN;
}
}
while (pos < len) {
if (data[pos] == '\\') {
if (pos + 1 >= len) {
return kUnclosed;
}
ret = kEscaped;
pos += 2;
continue;
}
if (data[pos++] == '"') {
return ret;
}
};
return kUnclosed;
}

template <typename T>
sonic_force_inline uint64_t GetStringBits(const uint8_t *data,
uint64_t &prev_instring,
uint64_t &prev_escaped) {
const T v(data);
uint64_t escaped = 0;
uint64_t bs_bits = v.eq('\\');
if (bs_bits) {
escaped = common::GetEscaped<64>(prev_escaped, bs_bits);
} else {
escaped = prev_escaped;
prev_escaped = 0;
}
uint64_t quote_bits = v.eq('"') & ~escaped;
uint64_t in_string = PrefixXor(quote_bits) ^ prev_instring;
prev_instring = uint64_t(static_cast<int64_t>(in_string) >> 63);
return in_string;
}

// GetNextToken find the next characters in tokens and update the position to
// it.
template <size_t N>
sonic_force_inline uint8_t GetNextToken(const uint8_t *data, size_t &pos,
size_t len, const char (&tokens)[N]) {
while (pos + VEC_LEN <= len) {
vuint8m1_t v = __riscv_vle8_v_u8m1(data + pos, 16);
vbool8_t vor = __riscv_vmclr_m_b8(16);
for (size_t i = 0; i < N - 1; i++) {
vbool8_t cmp_res = __riscv_vmseq_vv_u8m1_b8(
v, __riscv_vmv_v_x_u8m1((uint8_t)(tokens[i]), 16), 16);
vor = __riscv_vmor_mm_b8(vor, cmp_res, 16);
}

uint16_t next = to_bitmask(vor);
if (next) {
pos += TrailingZeroes(next);
return data[pos];
}
pos += VEC_LEN;
}
while (pos < len) {
for (size_t i = 0; i < N - 1; i++) {
if (data[pos] == tokens[i]) {
return tokens[i];
}
}
pos++;
}
return '\0';
}

template <typename T>
sonic_force_inline bool skip_container(const uint8_t *data, size_t &pos,
size_t len, uint8_t left,
uint8_t right) {
uint64_t prev_instring = 0, prev_escaped = 0, instring;
int rbrace_num = 0, lbrace_num = 0, last_lbrace_num;
const uint8_t *p;
while (pos + 64 <= len) {
p = data + pos;
#define SKIP_LOOP() \
{ \
instring = GetStringBits<T>(p, prev_instring, prev_escaped); \
T v(p); \
last_lbrace_num = lbrace_num; \
uint64_t rbrace = v.eq(right) & ~instring; \
uint64_t lbrace = v.eq(left) & ~instring; \
/* traverse each '}' */ \
while (rbrace > 0) { \
rbrace_num++; \
lbrace_num = last_lbrace_num + CountOnes((rbrace - 1) & lbrace); \
bool is_closed = lbrace_num < rbrace_num; \
if (is_closed) { \
sonic_assert(rbrace_num == lbrace_num + 1); \
pos += TrailingZeroes(rbrace) + 1; \
return true; \
} \
rbrace &= (rbrace - 1); \
} \
lbrace_num = last_lbrace_num + CountOnes(lbrace); \
}
SKIP_LOOP();
pos += 64;
}
uint8_t buf[64] = {0};
std::memcpy(buf, data + pos, len - pos);
p = buf;
SKIP_LOOP();
#undef SKIP_LOOP
return false;
}
35 changes: 35 additions & 0 deletions include/sonic/internal/arch/rvv-128/base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2022 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once
#include <sonic/macro.h>

#include <cstring>

#include "../common/riscv_common/base.h"

namespace sonic_json {
namespace internal {
namespace rvv_128 {
using sonic_json::internal::riscv_common::ClearLowestBit;
using sonic_json::internal::riscv_common::CountOnes;
using sonic_json::internal::riscv_common::LeadingZeroes;
using sonic_json::internal::riscv_common::PrefixXor;
using sonic_json::internal::riscv_common::TrailingZeroes;
using sonic_json::internal::riscv_common::Xmemcpy;
} // namespace rvv_128
} // namespace internal
} // namespace sonic_json
Loading