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
17 changes: 17 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ sse_copts = ['-msse', '-msse2', '-msse4.1', '-msse4.2','-mpclmul']
arm_copts = ['-march=armv8-a']
apple_silicon_copts = [ '-mcpu=apple-m1' ]
sve2_copts = ['-march=armv8-a+sve2', '-msve-vector-bits=128']
riscv64_copts = ['-march=rv64gc']
riscv64_zbb_copts = ['-march=rv64gc_zbb']
default_copts = ['-march=native']
benchmark_copts = ['-O3', '-DNDEBUG', '-std=c++17']
static_dispatch_copts = []
Expand All @@ -29,6 +31,7 @@ filesystem_linkopts = select({
string_flag(
name = "sonic_arch",
build_setting_default = "default",
values = ["default", "haswell", "westmere", "arm", "sve2", "riscv64", "riscv64_zbb"],
)

string_flag(
Expand Down Expand Up @@ -60,6 +63,16 @@ config_setting(
flag_values = {":sonic_arch": "sve2"},
)

config_setting(
name = "riscv64_build",
flag_values = {":sonic_arch": "riscv64"},
)

config_setting(
name = "riscv64_zbb_build",
flag_values = {":sonic_arch": "riscv64_zbb"},
)

config_setting(
name = "apple_silicon_build",
values = {"cpu": "darwin_arm64"},
Expand Down Expand Up @@ -136,6 +149,8 @@ cc_binary(
"sse_build": sse_copts + benchmark_copts,
"avx2_build": avx2_copts + benchmark_copts,
"apple_silicon_build": apple_silicon_copts + benchmark_copts,
"riscv64_build": riscv64_copts + benchmark_copts,
"riscv64_zbb_build": riscv64_zbb_copts + benchmark_copts,
"//conditions:default": default_copts + benchmark_copts,
}) +\
macos_version_copts +\
Expand Down Expand Up @@ -183,6 +198,8 @@ cc_test(
"sse_build": sse_copts + benchmark_copts,
"avx2_build": avx2_copts + benchmark_copts,
"apple_silicon_build": apple_silicon_copts + benchmark_copts,
"riscv64_build": riscv64_copts + benchmark_copts,
"riscv64_zbb_build": riscv64_zbb_copts + benchmark_copts,
"//conditions:default": default_copts + benchmark_copts,
}) +\
macos_version_copts +\
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,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_RISCV_ZBB "Enable RISC-V Zbb extension for bit manipulation optimizations" OFF)

set(CMAKE_CXX_EXTENSIONS OFF)
if(BUILD_UNITTEST)
Expand Down
6 changes: 6 additions & 0 deletions cmake/set_arch_flags.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ function(set_arch_flags target arch)
target_compile_options(${target} PRIVATE -march=armv8-a)
endif()
endif()
elseif(arch MATCHES "riscv64|riscv")
if(ENABLE_RISCV_ZBB)
target_compile_options(${target} PRIVATE -march=rv64gc_zbb)
else()
target_compile_options(${target} PRIVATE -march=rv64gc)
endif()
else()
message(FATAL_ERROR "Unsupported architecture: ${arch}")
endif()
Expand Down
3 changes: 2 additions & 1 deletion include/sonic/allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,9 @@ class SpinLock {
__builtin_ia32_pause();
#elif defined(__aarch64__) || defined(_M_ARM64)
asm volatile("yield");
#elif defined(__riscv)
__asm__ volatile("pause");
#endif

#endif
}
}
Expand Down
16 changes: 16 additions & 0 deletions include/sonic/dom/flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ enum ParseFlag {
kParseOverflowNumAsNumStr = 1 << 3,
};

// Scoped spelling used by newer downstream code while retaining the legacy
// ParseFlag template API on this branch.
struct ParseFlags {
static constexpr ParseFlag kParseDefault = ::kParseDefault;
static constexpr ParseFlag kParseAllowUnescapedControlChars =
::kParseAllowUnescapedControlChars;
static constexpr ParseFlag kParseIntegerAsRaw = ::kParseIntegerAsRaw;
static constexpr ParseFlag kParseOverflowNumAsNumStr =
::kParseOverflowNumAsNumStr;
};

constexpr ParseFlag operator|(ParseFlag lhs, ParseFlag rhs) {
return static_cast<ParseFlag>(static_cast<unsigned>(lhs) |
static_cast<unsigned>(rhs));
}

// SerializeFlags is one-hot encoded for different serializing option.
// User can define customed flags through combinations.
enum SerializeFlags {
Expand Down
78 changes: 78 additions & 0 deletions include/sonic/internal/arch/riscv/base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright 2018-2019 The simdjson authors

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

// This file may have been modified by ByteDance authors. All ByteDance
// Modifications are Copyright 2022 ByteDance Authors.

#pragma once

#include <sonic/macro.h>

#include <cstdint>
#include <cstring>

namespace sonic_json {
namespace internal {
namespace riscv {

// 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 __attribute__((no_sanitize("undefined"))) int TrailingZeroes(
uint64_t input_num) {
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);
}

sonic_force_inline bool InlinedMemcmpEq(const void* _a, const void* _b,
size_t s) {
return std::memcmp(_a, _b, s) == 0;
}

sonic_force_inline int InlinedMemcmp(const void* _l, const void* _r, size_t s) {
return std::memcmp(_l, _r, s);
}

} // namespace riscv
} // namespace internal
} // namespace sonic_json
85 changes: 85 additions & 0 deletions include/sonic/internal/arch/riscv/itoa.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* 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 <cstddef>
#include <cstdint>

namespace sonic_json {
namespace internal {
namespace riscv {

// Scalar implementation of Utoa_4_helper: convert num {abcd} to digits
static sonic_force_inline void Utoa_4_helper_scalar(uint16_t num,
uint8_t digits[4]) {
digits[0] = static_cast<uint8_t>((num / 1000) % 10);
digits[1] = static_cast<uint8_t>((num / 100) % 10);
digits[2] = static_cast<uint8_t>((num / 10) % 10);
digits[3] = static_cast<uint8_t>(num % 10);
}

// Convert num's each digit to bytes.
// num's digits as abcdefgh (high bits is 0 if not enough)
// The converted digits are { a, b, c, d, e, f, g, h }
static sonic_force_inline void Utoa_Scalar(uint32_t num, uint8_t digits[8]) {
uint16_t hi = static_cast<uint16_t>(num % 10000); // {efgh}
uint16_t lo = static_cast<uint16_t>(num / 10000); // {abcd}

uint8_t lo_digits[4];
uint8_t hi_digits[4];
Utoa_4_helper_scalar(lo, lo_digits);
Utoa_4_helper_scalar(hi, hi_digits);

digits[0] = lo_digits[0];
digits[1] = lo_digits[1];
digits[2] = lo_digits[2];
digits[3] = lo_digits[3];
digits[4] = hi_digits[0];
digits[5] = hi_digits[1];
digits[6] = hi_digits[2];
digits[7] = hi_digits[3];
}

static sonic_force_inline char *Utoa_8(uint32_t val, char *out) {
uint8_t digits[8];
Utoa_Scalar(val, digits);
for (int i = 0; i < 8; i++) {
out[i] = static_cast<char>('0' + digits[i]);
}
return out + 8;
}

static sonic_force_inline char *Utoa_16(uint64_t val, char *out) {
uint8_t digits_hi[8];
uint8_t digits_lo[8];
Utoa_Scalar(static_cast<uint32_t>(val / 100000000), digits_hi);
Utoa_Scalar(static_cast<uint32_t>(val % 100000000), digits_lo);

for (int i = 0; i < 8; i++) {
out[i] = static_cast<char>('0' + digits_hi[i]);
}
for (int i = 0; i < 8; i++) {
out[i + 8] = static_cast<char>('0' + digits_lo[i]);
}
return out + 16;
}

} // namespace riscv
} // namespace internal
} // namespace sonic_json
Loading