Basic AVX-512 implementation (icelake or better) (#1813)

* Add cascadelake implementation, which use AVX512 Intrinsics to optimize performance(#1811)

Co-authored-by: mellonyou <fangzheng.zhang@intel.com>
Co-authored-by: wanweiqiangintel <weiqiang.wan@intel.com>
This commit is contained in:
Daniel Lemire
2022-05-25 11:14:02 -04:00
committed by GitHub
parent 645033a8c8
commit e8f370b085
34 changed files with 1108 additions and 101 deletions
+8 -4
View File
@@ -8,7 +8,7 @@ steps:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
@@ -19,6 +19,7 @@ steps:
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ctest $CTEST_FLAGS -L acceptance -LE per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
@@ -35,7 +36,7 @@ steps:
CC: clang-6.0
CXX: clang++-6.0
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- mkdir build
@@ -43,6 +44,7 @@ steps:
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ctest $CTEST_FLAGS -L acceptance -LE per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
@@ -100,7 +102,7 @@ steps:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
@@ -111,6 +113,7 @@ steps:
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L acceptance -LE per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
@@ -126,7 +129,7 @@ steps:
environment:
CC: clang-9
CXX: clang++-9
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
@@ -135,6 +138,7 @@ steps:
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L acceptance -LE per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
+1 -1
View File
@@ -38,6 +38,6 @@ jobs:
run: |
mkdir build
cd build
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
cmake --build . --verbose
ctest -j4 --output-on-failure -LE explicitonly
+33
View File
@@ -0,0 +1,33 @@
name: Ubuntu 22.04 CI (GCC 11)
on: [push, pull_request]
jobs:
ubuntu-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir builddebug &&
cd builddebug &&
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cd .. &&
mkdir build &&
cd build &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
cd ../tests/installation_tests/find &&
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
+5 -5
View File
@@ -13,16 +13,16 @@ jobs:
fail-fast: false
matrix:
include:
- {gen: Visual Studio 17 2022, arch: Win32, static: ON}
- {gen: Visual Studio 17 2022, arch: Win32, static: OFF}
- {gen: Visual Studio 17 2022, arch: x64, static: ON}
- {gen: Visual Studio 17 2022, arch: x64, static: OFF}
- {gen: Visual Studio 17 2022, arch: Win32, shared: ON}
- {gen: Visual Studio 17 2022, arch: Win32, shared: OFF}
- {gen: Visual Studio 17 2022, arch: x64, shared: ON}
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
steps:
- name: checkout
uses: actions/checkout@v2
- name: Configure
run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_BUILD_STATIC=${{matrix.static}} -B build
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
- name: Build Debug
run: cmake --build build --config Debug --verbose
- name: Build Release
+29 -19
View File
@@ -9,23 +9,33 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-vs17
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- {gen: Visual Studio 17 2022, arch: x64}
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: 'Run CMake with VS17 Clang'
uses: lukka/run-cmake@v3
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
buildDirectory: "${{ github.workspace }}/../../_temp/windows"
cmakeBuildType: Release
buildWithCMake: true
cmakeAppendedArgs: -T ClangCL -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
buildWithCMakeArgs: --config Release
- name: 'Run CTest'
run: ctest -C Release -LE explicitonly --output-on-failure
working-directory: "${{ github.workspace }}/../../_temp/windows"
- name: checkout
uses: actions/checkout@v2
- name: Configure
run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -T ClangCL -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
- name: Build Debug
run: cmake --build build --config Debug --verbose
- name: Build Release
run: cmake --build build --config Release --verbose
- name: Run Release tests
run: |
cd build
ctest -C Release -LE explicitonly --output-on-failure
- name: Run Debug tests
run: |
cd build
ctest -C Debug -LE explicitonly --output-on-failure
- name: Install
run: |
cmake --install build --config Release
- name: Test Installation
run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find
cmake --build build_install_test --config Release
-45
View File
@@ -1,45 +0,0 @@
name: VS17-Ninja-CI
on: [push, pull_request]
jobs:
ci:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-vs17
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: 'Run CMake with VS17'
uses: lukka/run-cmake@v2
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
buildDirectory: "${{ github.workspace }}/../../_temp/windows"
cmakeBuildType: Release
buildWithCMake: true
cmakeAppendedArgs: -G Ninja -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
buildWithCMakeArgs: --config Release
- name: 'Run CTest'
run: ctest -C Release -LE explicitonly --output-on-failure
working-directory: "${{ github.workspace }}/../../_temp/windows"
- name: 'Install with CMake'
uses: lukka/run-cmake@v3
with:
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
buildWithCMakeArgs: '--target install'
- name: 'Test Installation with CMake'
uses: lukka/run-cmake@v3
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/tests/installation_tests/find/CMakeLists.txt'
cmakeBuildType: Release
buildWithCMake: true
buildDirectory: '${{ github.workspace }}/tests/installation_tests/find/buildDirectory'
cmakeAppendedArgs: -G Ninja
buildWithCMakeArgs: '--config Release --verbose'
+4 -1
View File
@@ -38,5 +38,8 @@ Brendan Knapp
Danila Kutenin
Pavel Pavlov
Hao Chen
# if you have contributed to the project and your name does not
Nicolas Boyer
Kim Walisch and Jatin Bhateja (AVX-512 bitset decoder)
Eric Zhang (AVX-512 kernel)
# if you have contributed to the project and your name does not
# appear in this list, please let us know!
+2 -2
View File
@@ -50,9 +50,9 @@ simdjson_really_inline void simdjson_process_atom(stat_t &s,
} else if(element.is<double>()) {
s.float_count++;
} else if (element.is<bool>()) {
simdjson::error_code err;
bool v;
err = element.get(v);
simdjson::error_code error;
if ((error = element.get(v))) { std::cerr << error << std::endl; abort(); }
if (v) {
s.true_count++;
} else {
+12
View File
@@ -175,6 +175,18 @@ if(CMAKE_C_COMPILER_ID MATCHES "Intel")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-intel")
endif()
option(
SIMDJSON_AVX512_ALLOWED
"Enable AVX-512 instructions (only affects processors and compilers with AVX-512 support)."
ON
)
if(SIMDJSON_AVX512_ALLOWED)
add_compile_definitions(SIMDJSON_AVX512_ALLOWED=1)
else()
add_compile_definitions(SIMDJSON_AVX512_ALLOWED=0)
message(STATUS "AVX-512 instructions are not allowed.")
endif()
include(CheckSymbolExists)
check_symbol_exists(fork unistd.h HAVE_POSIX_FORK)
check_symbol_exists(wait sys/wait.h HAVE_POSIX_WAIT)
+2 -2
View File
@@ -1,7 +1,7 @@
#
# Implementation selection
#
set(SIMDJSON_ALL_IMPLEMENTATIONS fallback westmere haswell arm64 ppc64)
set(SIMDJSON_ALL_IMPLEMENTATIONS fallback westmere haswell icelake arm64 ppc64)
set(
SIMDJSON_IMPLEMENTATION ""
@@ -15,7 +15,7 @@ set(
SIMDJSON_EXCLUDE_IMPLEMENTATION ""
CACHE STRING "\
Semicolon-separated list of implementations to exclude \
(haswell/westmere/arm64/ppc64/fallback). By default, excludes any \
(icelake/haswell/westmere/arm64/ppc64/fallback). By default, excludes any \
implementations that are unsupported at compile time or cannot be selected at \
runtime."
)
+3 -1
View File
@@ -160,6 +160,8 @@ You should not expect the simdjson library to cause *downclocking* of your recen
- [Whenever 512-bit AVX-512 instructions are used](https://lemire.me/blog/2018/09/07/avx-512-when-and-how-to-use-these-new-instructions/).
- Whenever heavy 256-bit or wider instructions are used. Heavy instructions are those involving floating point operations or integer multiplications (since these execute on the floating point unit).
The simdjson library does not currently support AVX-512 instructions and it does not make use of heavy 256-bit instructions. We do use vectorized multiplications, but only using 128-bit registers. Thus there should be no downclocking due to simdjson on recent processors.
The simdjson library does not make use of heavy 256-bit instructions. We do use vectorized multiplications, but only using 128-bit registers. Thus there should be no downclocking due to simdjson on recent processors, except when AVX-512 is allowed and
detected. However, we only allow AVX-512 on recent processors (Ice Lake/Tiger Lake or better) where [little to no frequency throttling is expected](https://travisdowns.github.io/blog/2020/08/19/icl-avx512-freq.html). If you can still concerned, you can easily disable AVX-512 with the CMake option `SIMDJSON_AVX512_ALLOWED` set to `OFF` (e.g., `cmake -D SIMDJSON_AVX512_ALLOWED=OFF -B build && cmake --build build`) or by setting
the macro `SIMDJSON_AVX512_ALLOWED` to `0` in C++ prior to importing the headers.
You may still be worried about which SIMD instruction set is used by simdjson. Thankfully, [you can always determine and change which architecture-specific implementation is used](implementation-selection.md) by simdjson. Thus even if your CPU supports AVX2, you do not need to use AVX2. You are in control.
+3 -1
View File
@@ -5,7 +5,9 @@
// Determine the best builtin implementation
#ifndef SIMDJSON_BUILTIN_IMPLEMENTATION
#if SIMDJSON_CAN_ALWAYS_RUN_HASWELL
#if SIMDJSON_CAN_ALWAYS_RUN_ICELAKE
#define SIMDJSON_BUILTIN_IMPLEMENTATION icelake
#elif SIMDJSON_CAN_ALWAYS_RUN_HASWELL
#define SIMDJSON_BUILTIN_IMPLEMENTATION haswell
#elif SIMDJSON_CAN_ALWAYS_RUN_WESTMERE
#define SIMDJSON_BUILTIN_IMPLEMENTATION westmere
+1 -5
View File
@@ -41,11 +41,7 @@
// has it as a macro.
#ifndef _blsr_u64
// we roll our own
SIMDJSON_TARGET_HASWELL
static simdjson_really_inline uint64_t _blsr_u64(uint64_t n) {
return (n - 1) & n;
}
SIMDJSON_UNTARGET_HASWELL
#define _blsr_u64(n) ((n - 1) & n)
#endif // _blsr_u64
#endif // SIMDJSON_CLANG_VISUAL_STUDIO
+47
View File
@@ -0,0 +1,47 @@
#ifndef SIMDJSON_ICELAKE_H
#define SIMDJSON_ICELAKE_H
#include "simdjson/implementation-base.h"
#if SIMDJSON_IMPLEMENTATION_ICELAKE
#if SIMDJSON_CAN_ALWAYS_RUN_ICELAKE
#define SIMDJSON_TARGET_ICELAKE
#define SIMDJSON_UNTARGET_ICELAKE
#else
#define SIMDJSON_TARGET_ICELAKE SIMDJSON_TARGET_REGION("avx512f,avx512dq,avx512cd,avx512bw,avx512vbmi,avx512vbmi2,avx512vl,avx2,bmi,pclmul,lzcnt")
#define SIMDJSON_UNTARGET_ICELAKE SIMDJSON_UNTARGET_REGION
#endif
namespace simdjson {
/**
* Implementation for Icelake (Intel AVX512).
*/
namespace icelake {
} // namespace icelake
} // namespace simdjson
//
// These two need to be included outside SIMDJSON_TARGET_ICELAKE
//
#include "simdjson/icelake/implementation.h"
#include "simdjson/icelake/intrinsics.h"
//
// The rest need to be inside the region
//
#include "simdjson/icelake/begin.h"
// Declarations
#include "simdjson/generic/dom_parser_implementation.h"
#include "simdjson/icelake/bitmanipulation.h"
#include "simdjson/icelake/bitmask.h"
#include "simdjson/icelake/simd.h"
#include "simdjson/generic/jsoncharutils.h"
#include "simdjson/generic/atomparsing.h"
#include "simdjson/icelake/stringparsing.h"
#include "simdjson/icelake/numberparsing.h"
#include "simdjson/icelake/end.h"
#endif // SIMDJSON_IMPLEMENTATION_ICELAKE
#endif // SIMDJSON_ICELAKE_H
+2
View File
@@ -0,0 +1,2 @@
#define SIMDJSON_IMPLEMENTATION icelake
SIMDJSON_TARGET_ICELAKE
@@ -0,0 +1,61 @@
#ifndef SIMDJSON_ICELAKE_BITMANIPULATION_H
#define SIMDJSON_ICELAKE_BITMANIPULATION_H
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
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
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
return (int)_tzcnt_u64(input_num);
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
////////
// 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);
#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
}
/* result might be undefined when input_num is zero */
simdjson_really_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return _blsr_u64(input_num);
}
/* result might be undefined when input_num is zero */
simdjson_really_inline int leading_zeroes(uint64_t input_num) {
return int(_lzcnt_u64(input_num));
}
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_really_inline unsigned __int64 count_ones(uint64_t input_num) {
// note: we do not support legacy 32-bit Windows
return __popcnt64(input_num);// Visual Studio wants two underscores
}
#else
simdjson_really_inline long long int count_ones(uint64_t input_num) {
return _popcnt64(input_num);
}
#endif
simdjson_really_inline bool add_overflow(uint64_t value1, uint64_t value2,
uint64_t *result) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
return _addcarry_u64(0, value1, value2,
reinterpret_cast<unsigned __int64 *>(result));
#else
return __builtin_uaddll_overflow(value1, value2,
reinterpret_cast<unsigned long long *>(result));
#endif
}
} // unnamed namespace
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#endif // SIMDJSON_ICELAKE_BITMANIPULATION_H
+25
View File
@@ -0,0 +1,25 @@
#ifndef SIMDJSON_ICELAKE_BITMASK_H
#define SIMDJSON_ICELAKE_BITMASK_H
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
namespace {
//
// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
//
// For example, prefix_xor(00100100) == 00011100
//
simdjson_really_inline uint64_t prefix_xor(const uint64_t bitmask) {
// There should be no such thing with a processor supporting avx2
// but not clmul.
__m128i all_ones = _mm_set1_epi8('\xFF');
__m128i result = _mm_clmulepi64_si128(_mm_set_epi64x(0ULL, bitmask), all_ones, 0);
return _mm_cvtsi128_si64(result);
}
} // unnamed namespace
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#endif // SIMDJSON_ICELAKE_BITMASK_H
+2
View File
@@ -0,0 +1,2 @@
SIMDJSON_UNTARGET_ICELAKE
#undef SIMDJSON_IMPLEMENTATION
+31
View File
@@ -0,0 +1,31 @@
#ifndef SIMDJSON_ICELAKE_IMPLEMENTATION_H
#define SIMDJSON_ICELAKE_IMPLEMENTATION_H
#include "simdjson/implementation.h"
// The constructor may be executed on any host, so we take care not to use SIMDJSON_TARGET_ICELAKE
namespace simdjson {
namespace icelake {
using namespace simdjson;
class implementation final : public simdjson::implementation {
public:
simdjson_really_inline implementation() : simdjson::implementation(
"icelake",
"Intel/AMD AVX512",
internal::instruction_set::AVX2 | internal::instruction_set::PCLMULQDQ | internal::instruction_set::BMI1 | internal::instruction_set::BMI2 | internal::instruction_set::AVX512F | internal::instruction_set::AVX512DQ | internal::instruction_set::AVX512CD | internal::instruction_set::AVX512BW | internal::instruction_set::AVX512VL | internal::instruction_set::AVX512VBMI2
) {}
simdjson_warn_unused error_code create_dom_parser_implementation(
size_t capacity,
size_t max_length,
std::unique_ptr<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 icelake
} // namespace simdjson
#endif // SIMDJSON_ICELAKE_IMPLEMENTATION_H
+56
View File
@@ -0,0 +1,56 @@
#ifndef SIMDJSON_ICELAKE_INTRINSICS_H
#define SIMDJSON_ICELAKE_INTRINSICS_H
#include "simdjson/base.h"
#ifdef SIMDJSON_VISUAL_STUDIO
// under clang within visual studio, this will include <x86intrin.h>
#include <intrin.h> // visual studio or clang
#else
#include <x86intrin.h> // elsewhere
#endif // SIMDJSON_VISUAL_STUDIO
#ifdef SIMDJSON_CLANG_VISUAL_STUDIO
/**
* You are not supposed, normally, to include these
* headers directly. Instead you should either include intrin.h
* or x86intrin.h. However, when compiling with clang
* under Windows (i.e., when _MSC_VER is set), these headers
* only get included *if* the corresponding features are detected
* from macros:
* e.g., if __AVX2__ is set... in turn, we normally set these
* macros by compiling against the corresponding architecture
* (e.g., arch:AVX2, -mavx2, etc.) which compiles the whole
* software with these advanced instructions. In simdjson, we
* want to compile the whole program for a generic target,
* and only target our specific kernels. As a workaround,
* we directly include the needed headers. These headers would
* normally guard against such usage, but we carefully included
* <x86intrin.h> (or <intrin.h>) before, so the headers
* are fooled.
*/
#include <bmiintrin.h> // for _blsr_u64
#include <lzcntintrin.h> // for __lzcnt64
#include <immintrin.h> // for most things (AVX2, AVX512, _popcnt64)
#include <smmintrin.h>
#include <tmmintrin.h>
#include <avxintrin.h>
#include <avx2intrin.h>
#include <wmmintrin.h> // for _mm_clmulepi64_si128
// Important: we need the AVX-512 headers:
#include <avx512fintrin.h>
#include <avx512dqintrin.h>
#include <avx512cdintrin.h>
#include <avx512bwintrin.h>
#include <avx512vlintrin.h>
#include <avx512vbmiintrin.h>
#include <avx512vbmi2intrin.h>
// unfortunately, we may not get _blsr_u64, but, thankfully, clang
// has it as a macro.
#ifndef _blsr_u64
// we roll our own
#define _blsr_u64(n) ((n - 1) & n)
#endif // _blsr_u64
#endif // SIMDJSON_CLANG_VISUAL_STUDIO
#endif // SIMDJSON_ICELAKE_INTRINSICS_H
+34
View File
@@ -0,0 +1,34 @@
#ifndef SIMDJSON_ICELAKE_NUMBERPARSING_H
#define SIMDJSON_ICELAKE_NUMBERPARSING_H
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
namespace {
static simdjson_really_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
// this actually computes *16* values so we are being wasteful.
const __m128i ascii0 = _mm_set1_epi8('0');
const __m128i mul_1_10 =
_mm_setr_epi8(10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1);
const __m128i mul_1_100 = _mm_setr_epi16(100, 1, 100, 1, 100, 1, 100, 1);
const __m128i mul_1_10000 =
_mm_setr_epi16(10000, 1, 10000, 1, 10000, 1, 10000, 1);
const __m128i input = _mm_sub_epi8(
_mm_loadu_si128(reinterpret_cast<const __m128i *>(chars)), ascii0);
const __m128i t1 = _mm_maddubs_epi16(input, mul_1_10);
const __m128i t2 = _mm_madd_epi16(t1, mul_1_100);
const __m128i t3 = _mm_packus_epi32(t2, t2);
const __m128i t4 = _mm_madd_epi16(t3, mul_1_10000);
return _mm_cvtsi128_si32(
t4); // only captures the sum of the first 8 digits, drop the rest
}
} // unnamed namespace
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#include "simdjson/generic/numberparsing.h"
#endif // SIMDJSON_ICELAKE_NUMBERPARSING_H
+339
View File
@@ -0,0 +1,339 @@
#ifndef SIMDJSON_ICELAKE_SIMD_H
#define SIMDJSON_ICELAKE_SIMD_H
#include "simdjson/internal/simdprune_tables.h"
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
namespace {
namespace simd {
// Forward-declared so they can be used by splat and friends.
template<typename Child>
struct base {
__m512i value;
// Zero constructor
simdjson_really_inline base() : value{__m512i()} {}
// Conversion from SIMD register
simdjson_really_inline base(const __m512i _value) : value(_value) {}
// Conversion to SIMD register
simdjson_really_inline operator const __m512i&() const { return this->value; }
simdjson_really_inline operator __m512i&() { return this->value; }
// Bit operations
simdjson_really_inline Child operator|(const Child other) const { return _mm512_or_si512(*this, other); }
simdjson_really_inline Child operator&(const Child other) const { return _mm512_and_si512(*this, other); }
simdjson_really_inline Child operator^(const Child other) const { return _mm512_xor_si512(*this, other); }
simdjson_really_inline Child bit_andnot(const Child other) const { return _mm512_andnot_si512(other, *this); }
simdjson_really_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
simdjson_really_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
simdjson_really_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
};
// Forward-declared so they can be used by splat and friends.
template<typename T>
struct simd8;
template<typename T, typename Mask=simd8<bool>>
struct base8: base<simd8<T>> {
typedef uint32_t bitmask_t;
typedef uint64_t bitmask2_t;
simdjson_really_inline base8() : base<simd8<T>>() {}
simdjson_really_inline base8(const __m512i _value) : base<simd8<T>>(_value) {}
simdjson_really_inline uint64_t operator==(const simd8<T> other) const { return _mm512_cmpeq_epi8_mask(*this, other); }
static const int SIZE = sizeof(base<T>::value);
template<int N=1>
simdjson_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
return _mm512_alignr_epi8(*this, _mm512_permutex2var_epi64(prev_chunk, _mm512_set_epi64(13, 12, 11, 10, 9, 8, 7, 6), *this), 16 - N);
}
};
// SIMD byte mask type (returned by things like eq and gt)
template<>
struct simd8<bool>: base8<bool> {
static simdjson_really_inline simd8<bool> splat(bool _value) { return _mm512_set1_epi8(uint8_t(-(!!_value))); }
simdjson_really_inline simd8<bool>() : base8() {}
simdjson_really_inline simd8<bool>(const __m512i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_really_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_really_inline bool any() const { return !!_mm512_test_epi8_mask (*this, *this); }
simdjson_really_inline simd8<bool> operator~() const { return *this ^ true; }
};
template<typename T>
struct base8_numeric: base8<T> {
static simdjson_really_inline simd8<T> splat(T _value) { return _mm512_set1_epi8(_value); }
static simdjson_really_inline simd8<T> zero() { return _mm512_setzero_si512(); }
static simdjson_really_inline simd8<T> load(const T values[64]) {
return _mm512_loadu_si512(reinterpret_cast<const __m512i *>(values));
}
// Repeat 16 values as many times as necessary (usually for lookup tables)
static simdjson_really_inline simd8<T> repeat_16(
T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7,
T v8, T v9, T v10, T v11, T v12, T v13, T v14, T v15
) {
return simd8<T>(
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15,
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15,
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15,
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15
);
}
simdjson_really_inline base8_numeric() : base8<T>() {}
simdjson_really_inline base8_numeric(const __m512i _value) : base8<T>(_value) {}
// Store to array
simdjson_really_inline void store(T dst[64]) const { return _mm512_storeu_si512(reinterpret_cast<__m512i *>(dst), *this); }
// Addition/subtraction are the same for signed and unsigned
simdjson_really_inline simd8<T> operator+(const simd8<T> other) const { return _mm512_add_epi8(*this, other); }
simdjson_really_inline simd8<T> operator-(const simd8<T> other) const { return _mm512_sub_epi8(*this, other); }
simdjson_really_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
simdjson_really_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
// Override to distinguish from bool version
simdjson_really_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
// Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
template<typename L>
simdjson_really_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
return _mm512_shuffle_epi8(lookup_table, *this);
}
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
// Passing a 0 value for mask would be equivalent to writing out every byte to output.
// Only the first 32 - count_ones(mask) bytes of the result are significant but 32 bytes
// get written.
// Design consideration: it seems like a function with the
// signature simd8<L> compress(uint32_t mask) would be
// sensible, but the AVX ISA makes this kind of approach difficult.
template<typename L>
simdjson_really_inline void compress(uint64_t mask, L * output) const {
_mm512_mask_compressstoreu_epi8 (output,~mask,*this);
}
template<typename L>
simdjson_really_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> : base8_numeric<int8_t> {
simdjson_really_inline simd8() : base8_numeric<int8_t>() {}
simdjson_really_inline simd8(const __m512i _value) : base8_numeric<int8_t>(_value) {}
// Splat constructor
simdjson_really_inline simd8(int8_t _value) : simd8(splat(_value)) {}
// Array constructor
simdjson_really_inline simd8(const int8_t values[64]) : simd8(load(values)) {}
// Member-by-member initialization
simdjson_really_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,
int8_t v16, int8_t v17, int8_t v18, int8_t v19, int8_t v20, int8_t v21, int8_t v22, int8_t v23,
int8_t v24, int8_t v25, int8_t v26, int8_t v27, int8_t v28, int8_t v29, int8_t v30, int8_t v31,
int8_t v32, int8_t v33, int8_t v34, int8_t v35, int8_t v36, int8_t v37, int8_t v38, int8_t v39,
int8_t v40, int8_t v41, int8_t v42, int8_t v43, int8_t v44, int8_t v45, int8_t v46, int8_t v47,
int8_t v48, int8_t v49, int8_t v50, int8_t v51, int8_t v52, int8_t v53, int8_t v54, int8_t v55,
int8_t v56, int8_t v57, int8_t v58, int8_t v59, int8_t v60, int8_t v61, int8_t v62, int8_t v63
) : simd8(_mm512_set_epi8(
v63, v62, v61, v60, v59, v58, v57, v56,
v55, v54, v53, v52, v51, v50, v49, v48,
v47, v46, v45, v44, v43, v42, v41, v40,
v39, v38, v37, v36, v35, v34, v33, v32,
v31, v30, v29, v28, v27, v26, v25, v24,
v23, v22, v21, v20, v19, v18, v17, v16,
v15, v14, v13, v12, v11, v10, v9, v8,
v7, v6, v5, v4, v3, v2, v1, v0
)) {}
// Repeat 16 values as many times as necessary (usually for lookup tables)
simdjson_really_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,
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15,
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15,
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15
);
}
// Order-sensitive comparisons
simdjson_really_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return _mm512_max_epi8(*this, other); }
simdjson_really_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return _mm512_min_epi8(*this, other); }
simdjson_really_inline simd8<bool> operator>(const simd8<int8_t> other) const { return _mm512_maskz_abs_epi8(_mm512_cmpgt_epi8_mask(*this, other),_mm512_set1_epi8(uint8_t(0x80))); }
simdjson_really_inline simd8<bool> operator<(const simd8<int8_t> other) const { return _mm512_maskz_abs_epi8(_mm512_cmpgt_epi8_mask(other, *this),_mm512_set1_epi8(uint8_t(0x80))); }
};
// Unsigned bytes
template<>
struct simd8<uint8_t>: base8_numeric<uint8_t> {
simdjson_really_inline simd8() : base8_numeric<uint8_t>() {}
simdjson_really_inline simd8(const __m512i _value) : base8_numeric<uint8_t>(_value) {}
// Splat constructor
simdjson_really_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
// Array constructor
simdjson_really_inline simd8(const uint8_t values[64]) : simd8(load(values)) {}
// Member-by-member initialization
simdjson_really_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,
uint8_t v16, uint8_t v17, uint8_t v18, uint8_t v19, uint8_t v20, uint8_t v21, uint8_t v22, uint8_t v23,
uint8_t v24, uint8_t v25, uint8_t v26, uint8_t v27, uint8_t v28, uint8_t v29, uint8_t v30, uint8_t v31,
uint8_t v32, uint8_t v33, uint8_t v34, uint8_t v35, uint8_t v36, uint8_t v37, uint8_t v38, uint8_t v39,
uint8_t v40, uint8_t v41, uint8_t v42, uint8_t v43, uint8_t v44, uint8_t v45, uint8_t v46, uint8_t v47,
uint8_t v48, uint8_t v49, uint8_t v50, uint8_t v51, uint8_t v52, uint8_t v53, uint8_t v54, uint8_t v55,
uint8_t v56, uint8_t v57, uint8_t v58, uint8_t v59, uint8_t v60, uint8_t v61, uint8_t v62, uint8_t v63
) : simd8(_mm512_set_epi8(
v63, v62, v61, v60, v59, v58, v57, v56,
v55, v54, v53, v52, v51, v50, v49, v48,
v47, v46, v45, v44, v43, v42, v41, v40,
v39, v38, v37, v36, v35, v34, v33, v32,
v31, v30, v29, v28, v27, v26, v25, v24,
v23, v22, v21, v20, v19, v18, v17, v16,
v15, v14, v13, v12, v11, v10, v9, v8,
v7, v6, v5, v4, v3, v2, v1, v0
)) {}
// Repeat 16 values as many times as necessary (usually for lookup tables)
simdjson_really_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,
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15,
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15,
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15
);
}
// Saturated math
simdjson_really_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return _mm512_adds_epu8(*this, other); }
simdjson_really_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return _mm512_subs_epu8(*this, other); }
// Order-specific operations
simdjson_really_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return _mm512_max_epu8(*this, other); }
simdjson_really_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return _mm512_min_epu8(other, *this); }
// Same as >, but only guarantees true is nonzero (< guarantees true = -1)
simdjson_really_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
// Same as <, but only guarantees true is nonzero (< guarantees true = -1)
simdjson_really_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
simdjson_really_inline uint64_t operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
simdjson_really_inline uint64_t operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
simdjson_really_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
simdjson_really_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->lt_bits(other).any_bits_set(); }
// Bit-specific operations
simdjson_really_inline simd8<bool> bits_not_set() const { return _mm512_mask_blend_epi8(*this == uint8_t(0), _mm512_set1_epi8(0), _mm512_set1_epi8(-1)); }
simdjson_really_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
simdjson_really_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
simdjson_really_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
simdjson_really_inline bool is_ascii() const { return _mm512_movepi8_mask(*this) == 0; }
simdjson_really_inline bool bits_not_set_anywhere() const {
return !_mm512_test_epi8_mask(*this, *this);
}
simdjson_really_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
simdjson_really_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const { return !_mm512_test_epi8_mask(*this, bits); }
simdjson_really_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
template<int N>
simdjson_really_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(_mm512_srli_epi16(*this, N)) & uint8_t(0xFFu >> N); }
template<int N>
simdjson_really_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(_mm512_slli_epi16(*this, N)) & uint8_t(0xFFu << N); }
// Get one of the bits and make a bitmask out of it.
// e.g. value.get_bit<7>() gets the high bit
template<int N>
simdjson_really_inline uint64_t get_bit() const { return _mm512_movepi8_mask(_mm512_slli_epi16(*this, 7-N)); }
};
template<typename T>
struct simd8x64 {
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];
simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
simd8x64() = delete; // no default constructor allowed
simdjson_really_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1) : chunks{chunk0, chunk1} {}
simdjson_really_inline simd8x64(const simd8<T> chunk0) : chunks{chunk0} {}
simdjson_really_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr)} {}
simdjson_really_inline uint64_t compress(uint64_t mask, T * output) const {
this->chunks[0].compress(mask, output);
return 64 - count_ones(mask);
}
simdjson_really_inline void store(T ptr[64]) const {
this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
}
simdjson_really_inline simd8<T> reduce_or() const {
return this->chunks[0];
}
simdjson_really_inline simd8x64<T> bit_or(const T m) const {
const simd8<T> mask = simd8<T>::splat(m);
return simd8x64<T>(
this->chunks[0] | mask
);
}
simdjson_really_inline uint64_t eq(const T m) const {
const simd8<T> mask = simd8<T>::splat(m);
return this->chunks[0] == mask;
}
simdjson_really_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
return this->chunks[0] == other.chunks[0];
}
simdjson_really_inline uint64_t lteq(const T m) const {
const simd8<T> mask = simd8<T>::splat(m);
return this->chunks[0] <= mask;
}
}; // struct simd8x64<T>
} // namespace simd
} // unnamed namespace
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#endif // SIMDJSON_ICELAKE_SIMD_H
+48
View File
@@ -0,0 +1,48 @@
#ifndef SIMDJSON_ICELAKE_STRINGPARSING_H
#define SIMDJSON_ICELAKE_STRINGPARSING_H
#include "simdjson/base.h"
#include "simdjson/icelake/simd.h"
#include "simdjson/icelake/bitmanipulation.h"
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
namespace {
using namespace simd;
// Holds backslashes and quotes locations.
struct backslash_and_quote {
public:
static constexpr uint32_t BYTES_PROCESSED = 32;
simdjson_really_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
simdjson_really_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
simdjson_really_inline bool has_backslash() { return ((quote_bits - 1) & bs_bits) != 0; }
simdjson_really_inline int quote_index() { return trailing_zeroes(quote_bits); }
simdjson_really_inline int backslash_index() { return trailing_zeroes(bs_bits); }
uint64_t bs_bits;
uint64_t quote_bits;
}; // struct backslash_and_quote
simdjson_really_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
// this can read up to 15 bytes beyond the buffer size, but we require
// 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);
// store to dest unconditionally - we can overwrite the bits we don't like later
v.store(dst);
return {
static_cast<uint64_t>(v == '\\'), // bs_bits
static_cast<uint64_t>(v == '"'), // quote_bits
};
}
} // unnamed namespace
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#include "simdjson/generic/stringparsing.h"
#endif // SIMDJSON_ICELAKE_STRINGPARSING_H
+25 -2
View File
@@ -13,10 +13,32 @@
#endif
#define SIMDJSON_CAN_ALWAYS_RUN_ARM64 SIMDJSON_IMPLEMENTATION_ARM64 && SIMDJSON_IS_ARM64
#ifdef __has_include
// How do we detect that a compiler supports vbmi2?
// For sure if the following header is found, we are ok?
#if __has_include(<avx512vbmi2intrin.h>)
#define SIMDJSON_COMPILER_SUPPORTS_VBMI2 1
#endif
#endif
// Default Icelake to on if this is x86-64. Even if we're not compiled for it, it could be selected
// at runtime.
#ifndef SIMDJSON_IMPLEMENTATION_ICELAKE
#define SIMDJSON_IMPLEMENTATION_ICELAKE ((SIMDJSON_IS_X86_64) && (SIMDJSON_AVX512_ALLOWED) && (SIMDJSON_COMPILER_SUPPORTS_VBMI2))
#endif
#ifdef _MSC_VER
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
// https://github.com/simdjson/simdjson/issues/1247
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
#else
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
#endif
// Default Haswell to on if this is x86-64. Even if we're not compiled for it, it could be selected
// at runtime.
#ifndef SIMDJSON_IMPLEMENTATION_HASWELL
#define SIMDJSON_IMPLEMENTATION_HASWELL (SIMDJSON_IS_X86_64)
#define SIMDJSON_IMPLEMENTATION_HASWELL SIMDJSON_IS_X86_64
#endif
#ifdef _MSC_VER
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
@@ -26,7 +48,7 @@
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
#endif
// Default Westmere to on if this is x86-64, unless we'll always select Haswell.
// Default Westmere to on if this is x86-64. Note that the macro SIMDJSON_REQUIRES_HASWELL appears unused.
#ifndef SIMDJSON_IMPLEMENTATION_WESTMERE
#define SIMDJSON_IMPLEMENTATION_WESTMERE (SIMDJSON_IS_X86_64 && !SIMDJSON_REQUIRES_HASWELL)
#endif
@@ -49,6 +71,7 @@ SIMDJSON_DISABLE_UNDESIRED_WARNINGS
// Implementations
#include "simdjson/arm64.h"
#include "simdjson/fallback.h"
#include "simdjson/icelake.h"
#include "simdjson/haswell.h"
#include "simdjson/ppc64.h"
#include "simdjson/westmere.h"
+60 -6
View File
@@ -66,7 +66,16 @@ enum instruction_set {
PCLMULQDQ = 0x10,
BMI1 = 0x20,
BMI2 = 0x40,
ALTIVEC = 0x80
ALTIVEC = 0x80,
AVX512F = 0x100,
AVX512DQ = 0x200,
AVX512IFMA = 0x400,
AVX512PF = 0x800,
AVX512ER = 0x1000,
AVX512CD = 0x2000,
AVX512BW = 0x4000,
AVX512VL = 0x8000,
AVX512VBMI2 = 0x10000
};
#if defined(__PPC64__)
@@ -96,11 +105,20 @@ static inline uint32_t detect_supported_architectures() {
namespace {
// Can be found on Intel ISA Reference for CPUID
constexpr uint32_t cpuid_avx2_bit = 1 << 5; ///< @private Bit 5 of EBX for EAX=0x7
constexpr uint32_t cpuid_bmi1_bit = 1 << 3; ///< @private bit 3 of EBX for EAX=0x7
constexpr uint32_t cpuid_bmi2_bit = 1 << 8; ///< @private bit 8 of EBX for EAX=0x7
constexpr uint32_t cpuid_sse42_bit = 1 << 20; ///< @private bit 20 of ECX for EAX=0x1
constexpr uint32_t cpuid_pclmulqdq_bit = 1 << 1; ///< @private bit 1 of ECX for EAX=0x1
constexpr uint32_t cpuid_avx2_bit = 1 << 5; ///< @private Bit 5 of EBX for EAX=0x7
constexpr uint32_t cpuid_bmi1_bit = 1 << 3; ///< @private bit 3 of EBX for EAX=0x7
constexpr uint32_t cpuid_bmi2_bit = 1 << 8; ///< @private bit 8 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512f_bit = 1 << 16; ///< @private bit 16 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512dq_bit = 1 << 17; ///< @private bit 17 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512ifma_bit = 1 << 21; ///< @private bit 21 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512pf_bit = 1 << 26; ///< @private bit 26 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512er_bit = 1 << 27; ///< @private bit 27 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512cd_bit = 1 << 28; ///< @private bit 28 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512bw_bit = 1 << 30; ///< @private bit 30 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512vl_bit = 1 << 31; ///< @private bit 31 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512vbmi2_bit = 1 << 6; ///< @private bit 6 of ECX for EAX=0x7
constexpr uint32_t cpuid_sse42_bit = 1 << 20; ///< @private bit 20 of ECX for EAX=0x1
constexpr uint32_t cpuid_pclmulqdq_bit = 1 << 1; ///< @private bit 1 of ECX for EAX=0x1
}
@@ -146,6 +164,42 @@ static inline uint32_t detect_supported_architectures() {
host_isa |= instruction_set::BMI2;
}
if (ebx & cpuid_avx512f_bit) {
host_isa |= instruction_set::AVX512F;
}
if (ebx & cpuid_avx512dq_bit) {
host_isa |= instruction_set::AVX512DQ;
}
if (ebx & cpuid_avx512ifma_bit) {
host_isa |= instruction_set::AVX512IFMA;
}
if (ebx & cpuid_avx512pf_bit) {
host_isa |= instruction_set::AVX512PF;
}
if (ebx & cpuid_avx512er_bit) {
host_isa |= instruction_set::AVX512ER;
}
if (ebx & cpuid_avx512cd_bit) {
host_isa |= instruction_set::AVX512CD;
}
if (ebx & cpuid_avx512bw_bit) {
host_isa |= instruction_set::AVX512BW;
}
if (ebx & cpuid_avx512vl_bit) {
host_isa |= instruction_set::AVX512VL;
}
if (ecx & cpuid_avx512vbmi2_bit) {
host_isa |= instruction_set::AVX512VBMI2;
}
// EBX for EAX=0x1
eax = 0x1;
cpuid(&eax, &ebx, &ecx, &edx);
@@ -25,6 +25,12 @@ public:
// base_ptr[base] incrementing base as we go
// will potentially store extra values beyond end of valid bits, so base_ptr
// needs to be large enough to handle this
//
// If the kernel sets SIMDJSON_CUSTOM_BIT_INDEXER, then it will provide its own
// version of the code.
#ifdef SIMDJSON_CUSTOM_BIT_INDEXER
simdjson_really_inline void write(uint32_t idx, uint64_t bits);
#else
simdjson_really_inline void write(uint32_t idx, uint64_t bits) {
// In some instances, the next branch is expensive because it is mispredicted.
// Unfortunately, in other cases,
@@ -117,6 +123,8 @@ public:
this->tail += cnt;
#endif
}
#endif // SIMDJSON_CUSTOM_BIT_INDEXER
};
class json_structural_indexer {
+20 -3
View File
@@ -111,12 +111,25 @@ using namespace simd;
simdjson_really_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
static const uint8_t max_array[64] = {
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 0b11110000u-1, 0b11100000u-1, 0b11000000u-1
};
#else
static const uint8_t max_array[32] = {
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 0b11110000u-1, 0b11100000u-1, 0b11000000u-1
};
#endif
const simd8<uint8_t> max_value(&max_array[sizeof(max_array)-sizeof(simd8<uint8_t>)]);
return input.gt_bits(max_value);
}
@@ -154,9 +167,13 @@ using namespace simd;
this->error |= this->prev_incomplete;
} else {
// you might think that a for-loop would work, but under Visual Studio, it is not good enough.
static_assert((simd8x64<uint8_t>::NUM_CHUNKS == 2) || (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support either two or four chunks per 64-byte block.");
if(simd8x64<uint8_t>::NUM_CHUNKS == 2) {
static_assert((simd8x64<uint8_t>::NUM_CHUNKS == 1)
||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block.");
if(simd8x64<uint8_t>::NUM_CHUNKS == 1) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
} if(simd8x64<uint8_t>::NUM_CHUNKS == 2) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
} else if(simd8x64<uint8_t>::NUM_CHUNKS == 4) {
+206
View File
@@ -0,0 +1,206 @@
#include "simdjson/icelake/begin.h"
//
// Stage 1
//
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
namespace {
using namespace simd;
struct json_character_block {
static simdjson_really_inline json_character_block classify(const simd::simd8x64<uint8_t>& in);
// ASCII white-space ('\r','\n','\t',' ')
simdjson_really_inline uint64_t whitespace() const noexcept;
// non-quote structural characters (comma, colon, braces, brackets)
simdjson_really_inline uint64_t op() const noexcept;
// neither a structural character nor a white-space, so letters, numbers and quotes
simdjson_really_inline uint64_t scalar() const noexcept;
uint64_t _whitespace; // ASCII white-space ('\r','\n','\t',' ')
uint64_t _op; // structural characters (comma, colon, braces, brackets but not quotes)
};
simdjson_really_inline uint64_t json_character_block::whitespace() const noexcept { return _whitespace; }
simdjson_really_inline uint64_t json_character_block::op() const noexcept { return _op; }
simdjson_really_inline uint64_t json_character_block::scalar() const noexcept { return ~(op() | whitespace()); }
// This identifies structural characters (comma, colon, braces, brackets),
// and ASCII white-space ('\r','\n','\t',' ').
simdjson_really_inline json_character_block json_character_block::classify(const simd::simd8x64<uint8_t>& in) {
// These lookups rely on the fact that anything < 127 will match the lower 4 bits, which is why
// we can't use the generic lookup_16.
const auto whitespace_table = simd8<uint8_t>::repeat_16(' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100);
// The 6 operators (:,[]{}) have these values:
//
// , 2C
// : 3A
// [ 5B
// { 7B
// ] 5D
// } 7D
//
// If you use | 0x20 to turn [ and ] into { and }, the lower 4 bits of each character is unique.
// We exploit this, using a simd 4-bit lookup to tell us which character match against, and then
// match it (against | 0x20).
//
// To prevent recognizing other characters, everything else gets compared with 0, which cannot
// match due to the | 0x20.
//
// NOTE: Due to the | 0x20, this ALSO treats <FF> and <SUB> (control characters 0C and 1A) like ,
// and :. This gets caught in stage 2, which checks the actual character to ensure the right
// operators are in the right places.
const auto op_table = simd8<uint8_t>::repeat_16(
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, ':', '{', // : = 3A, [ = 5B, { = 7B
',', '}', 0, 0 // , = 2C, ] = 5D, } = 7D
);
// We compute whitespace and op separately. If later code only uses one or the
// other, given the fact that all functions are aggressively inlined, we can
// hope that useless computations will be omitted. This is namely case when
// minifying (we only need whitespace).
const uint64_t whitespace = in.eq({
_mm512_shuffle_epi8(whitespace_table, in.chunks[0])
});
// Turn [ and ] into { and }
const simd8x64<uint8_t> curlified{
in.chunks[0] | 0x20
};
const uint64_t op = curlified.eq({
_mm512_shuffle_epi8(op_table, in.chunks[0])
});
return { whitespace, op };
}
simdjson_really_inline bool is_ascii(const simd8x64<uint8_t>& input) {
return input.reduce_or().is_ascii();
}
simdjson_unused simdjson_really_inline simd8<bool> must_be_continuation(const simd8<uint8_t> prev1, const simd8<uint8_t> prev2, const simd8<uint8_t> prev3) {
simd8<uint8_t> is_second_byte = prev1.saturating_sub(0b11000000u-1); // Only 11______ will be > 0
simd8<uint8_t> is_third_byte = prev2.saturating_sub(0b11100000u-1); // Only 111_____ will be > 0
simd8<uint8_t> is_fourth_byte = prev3.saturating_sub(0b11110000u-1); // Only 1111____ will be > 0
// Caller requires a bool (all 1's). All values resulting from the subtraction will be <= 64, so signed comparison is fine.
return simd8<int8_t>(is_second_byte | is_third_byte | is_fourth_byte) > int8_t(0);
}
simdjson_really_inline simd8<bool> must_be_2_3_continuation(const simd8<uint8_t> prev2, const simd8<uint8_t> prev3) {
simd8<uint8_t> is_third_byte = prev2.saturating_sub(0b11100000u-1); // Only 111_____ will be > 0
simd8<uint8_t> is_fourth_byte = prev3.saturating_sub(0b11110000u-1); // Only 1111____ will be > 0
// Caller requires a bool (all 1's). All values resulting from the subtraction will be <= 64, so signed comparison is fine.
return simd8<int8_t>(is_third_byte | is_fourth_byte) > int8_t(0);
}
} // unnamed namespace
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#include "generic/stage1/utf8_lookup4_algorithm.h"
// defining SIMDJSON_CUSTOM_BIT_INDEXER allows us to provide our own bit_indexer::write
#define SIMDJSON_CUSTOM_BIT_INDEXER
#include "generic/stage1/json_structural_indexer.h"
// We must not forget to undefine it now:
#undef SIMDJSON_CUSTOM_BIT_INDEXER
/**
* We provide a custom version of bit_indexer::write using
* naked intrinsics.
* TODO: make this code more elegant.
*/
namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace { namespace stage1 {
simdjson_really_inline void bit_indexer::write(uint32_t idx, uint64_t bits) {
// In some instances, the next branch is expensive because it is mispredicted.
// Unfortunately, in other cases,
// it helps tremendously.
if (bits == 0) { return; }
const __m512i indexes = _mm512_maskz_compress_epi8(bits, _mm512_set_epi32(
0x3f3e3d3c, 0x3b3a3938, 0x37363534, 0x33323130,
0x2f2e2d2c, 0x2b2a2928, 0x27262524, 0x23222120,
0x1f1e1d1c, 0x1b1a1918, 0x17161514, 0x13121110,
0x0f0e0d0c, 0x0b0a0908, 0x07060504, 0x03020100
));
const __m512i start_index = _mm512_set1_epi32(idx);
const auto count = count_ones(bits);
__m512i t0 = _mm512_cvtepu8_epi32(_mm512_castsi512_si128(indexes));
_mm512_storeu_si512(this->tail, _mm512_add_epi32(t0, start_index));
if(count > 16) {
const __m512i t1 = _mm512_cvtepu8_epi32(_mm512_extracti32x4_epi32(indexes, 1));
_mm512_storeu_si512(this->tail + 16, _mm512_add_epi32(t1, start_index));
if(count > 32) {
const __m512i t2 = _mm512_cvtepu8_epi32(_mm512_extracti32x4_epi32(indexes, 2));
_mm512_storeu_si512(this->tail + 32, _mm512_add_epi32(t2, start_index));
if(count > 48) {
const __m512i t3 = _mm512_cvtepu8_epi32(_mm512_extracti32x4_epi32(indexes, 3));
_mm512_storeu_si512(this->tail + 48, _mm512_add_epi32(t3, start_index));
}
}
}
this->tail += count;
}
}}}}
#include "generic/stage1/utf8_validator.h"
//
// Stage 2
//
#include "generic/stage2/tape_builder.h"
//
// Implementation-specific overrides
//
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
namespace {
namespace stage1 {
simdjson_really_inline uint64_t json_string_scanner::find_escaped(uint64_t backslash) {
if (!backslash) { uint64_t escaped = prev_escaped; prev_escaped = 0; return escaped; }
return find_escaped_branchless(backslash);
}
} // namespace stage1
} // unnamed namespace
simdjson_warn_unused error_code implementation::minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept {
return icelake::stage1::json_minifier::minify<128>(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 icelake::stage1::json_structural_indexer::index<128>(_buf, _len, *this, streaming);
}
simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t len) const noexcept {
return icelake::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_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 SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#include "simdjson/icelake/end.h"
+24
View File
@@ -0,0 +1,24 @@
#include "simdjson/icelake/begin.h"
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
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 SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#include "simdjson/icelake/end.h"
+9
View File
@@ -14,6 +14,12 @@ namespace internal {
// Static array of known implementations. We're hoping these get baked into the executable
// without requiring a static initializer.
#if SIMDJSON_IMPLEMENTATION_ICELAKE
static const icelake::implementation* get_icelake_singleton() {
static const icelake::implementation icelake_singleton{};
return &icelake_singleton;
}
#endif
#if SIMDJSON_IMPLEMENTATION_HASWELL
static const haswell::implementation* get_haswell_singleton() {
static const haswell::implementation haswell_singleton{};
@@ -73,6 +79,9 @@ private:
static const std::initializer_list<const implementation *>& get_available_implementation_pointers() {
static const std::initializer_list<const implementation *> available_implementation_pointers {
#if SIMDJSON_IMPLEMENTATION_ICELAKE
get_icelake_singleton(),
#endif
#if SIMDJSON_IMPLEMENTATION_HASWELL
get_haswell_singleton(),
#endif
+2 -2
View File
@@ -1,4 +1,4 @@
#if SIMDJSON_IMPLEMENTATION_ARM64 || SIMDJSON_IMPLEMENTATION_HASWELL || SIMDJSON_IMPLEMENTATION_WESTMERE || SIMDJSON_IMPLEMENTATION_PPC64
#if SIMDJSON_IMPLEMENTATION_ARM64 || SIMDJSON_IMPLEMENTATION_ICELAKE || SIMDJSON_IMPLEMENTATION_HASWELL || SIMDJSON_IMPLEMENTATION_WESTMERE || SIMDJSON_IMPLEMENTATION_PPC64
#include <cstdint>
@@ -128,4 +128,4 @@ SIMDJSON_DLLIMPORTEXPORT const uint64_t thintable_epi8[256] = {
} // namespace internal
} // namespace simdjson
#endif // SIMDJSON_IMPLEMENTATION_ARM64 || SIMDJSON_IMPLEMENTATION_HASWELL || SIMDJSON_IMPLEMENTATION_WESTMERE || SIMDJSON_IMPLEMENTATION_PPC64
#endif // SIMDJSON_IMPLEMENTATION_ARM64 || SIMDJSON_IMPLEMENTATION_ICELAKE || SIMDJSON_IMPLEMENTATION_HASWELL || SIMDJSON_IMPLEMENTATION_WESTMERE || SIMDJSON_IMPLEMENTATION_PPC64
+4
View File
@@ -19,6 +19,10 @@ SIMDJSON_DISABLE_UNDESIRED_WARNINGS
#include "fallback/implementation.cpp"
#include "fallback/dom_parser_implementation.cpp"
#endif
#if SIMDJSON_IMPLEMENTATION_ICELAKE
#include "icelake/implementation.cpp"
#include "icelake/dom_parser_implementation.cpp"
#endif
#if SIMDJSON_IMPLEMENTATION_HASWELL
#include "haswell/implementation.cpp"
#include "haswell/dom_parser_implementation.cpp"
@@ -16,7 +16,7 @@ namespace array_error_tests {
size_t count = 0;
for (auto elem : std::forward<T>(array)) {
std::cout << "-"; std::cout.flush();
V actual;
V actual{};
auto actual_error = elem.get(actual);
if (count >= N) {
if (count >= (N+N2)) {
+1 -1
View File
@@ -752,7 +752,7 @@ bool stream_capacity_example() {
if( error ) { /* handle the error */ }
for (auto doc: stream) {
if(counter < 6) {
int64_t val;
int64_t val{};
error = doc.at_pointer("/4").get(val);
if( error ) { /* handle the error */ }
std::cout << "5 = " << val << std::endl;