Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LoongArch LSX and LASX support #2159

Merged
merged 2 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 18 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,24 @@ if(
)
endif()

if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(loongarch64)$")
option(SIMDJSON_PREFER_LSX "Prefer LoongArch SX" ON)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-mlasx COMPILER_SUPPORTS_LASX)
check_cxx_compiler_flag(-mlsx COMPILER_SUPPORTS_LSX)
if(COMPILER_SUPPORTS_LASX AND NOT SIMDJSON_PREFER_LSX)
simdjson_add_props(
target_compile_options PRIVATE
-mlasx
)
elseif(COMPILER_SUPPORTS_LSX)
simdjson_add_props(
target_compile_options PRIVATE
-mlsx
)
endif()
endif()

# GCC and Clang have horrendous Debug builds when using SIMD.
# A common fix is to use '-Og' instead.
# bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412
Expand Down
4 changes: 4 additions & 0 deletions include/simdjson/builtin.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
#include "simdjson/ppc64.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
#include "simdjson/westmere.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lsx)
#include "simdjson/lsx.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
#include "simdjson/lasx.h"
#else
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
#endif
Expand Down
4 changes: 4 additions & 0 deletions include/simdjson/builtin/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ namespace simdjson {
namespace ppc64 {}
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
namespace westmere {}
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lsx)
namespace lsx {}
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
namespace lasx {}
#else
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
#endif
Expand Down
4 changes: 4 additions & 0 deletions include/simdjson/builtin/implementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#include "simdjson/ppc64/implementation.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
#include "simdjson/westmere/implementation.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lsx)
#include "simdjson/lsx/implementation.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
#include "simdjson/lasx/implementation.h"
#else
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
#endif
Expand Down
4 changes: 4 additions & 0 deletions include/simdjson/builtin/ondemand.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
#include "simdjson/ppc64/ondemand.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
#include "simdjson/westmere/ondemand.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lsx)
#include "simdjson/lsx/ondemand.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(lasx)
#include "simdjson/lasx/ondemand.h"
#else
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
#endif
Expand Down
4 changes: 4 additions & 0 deletions include/simdjson/generic/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
#include "simdjson/arm64/begin.h"
#elif SIMDJSON_IMPLEMENTATION_PPC64
#include "simdjson/ppc64/begin.h"
#elif SIMDJSON_IMPLEMENTATION_LSX
#include "simdjson/lsx/begin.h"
#elif SIMDJSON_IMPLEMENTATION_LASX
#include "simdjson/lasx/begin.h"
#elif SIMDJSON_IMPLEMENTATION_FALLBACK
#include "simdjson/fallback/begin.h"
#else
Expand Down
22 changes: 21 additions & 1 deletion include/simdjson/implementation_detection.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#define SIMDJSON_IMPLEMENTATION_ID_icelake 4
#define SIMDJSON_IMPLEMENTATION_ID_ppc64 5
#define SIMDJSON_IMPLEMENTATION_ID_westmere 6
#define SIMDJSON_IMPLEMENTATION_ID_lsx 7
#define SIMDJSON_IMPLEMENTATION_ID_lasx 8

#define SIMDJSON_IMPLEMENTATION_ID_FOR(IMPL) SIMDJSON_CAT(SIMDJSON_IMPLEMENTATION_ID_, IMPL)
#define SIMDJSON_IMPLEMENTATION_ID SIMDJSON_IMPLEMENTATION_ID_FOR(SIMDJSON_IMPLEMENTATION)
Expand Down Expand Up @@ -74,9 +76,23 @@
#endif
#define SIMDJSON_CAN_ALWAYS_RUN_PPC64 SIMDJSON_IMPLEMENTATION_PPC64 && SIMDJSON_IS_PPC64 && SIMDJSON_IS_PPC64_VMX

#ifndef SIMDJSON_IMPLEMENTATION_LASX
#define SIMDJSON_IMPLEMENTATION_LASX (SIMDJSON_IS_LOONGARCH64 && __loongarch_asx)
#endif
#define SIMDJSON_CAN_ALWAYS_RUN_LASX (SIMDJSON_IMPLEMENTATION_LASX)

#ifndef SIMDJSON_IMPLEMENTATION_LSX
#if SIMDJSON_CAN_ALWAYS_RUN_LASX
#define SIMDJSON_IMPLEMENTATION_LSX 0
#else
#define SIMDJSON_IMPLEMENTATION_LSX (SIMDJSON_IS_LOONGARCH64 && __loongarch_sx)
#endif
#endif
#define SIMDJSON_CAN_ALWAYS_RUN_LSX (SIMDJSON_IMPLEMENTATION_LSX)

// 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
#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
Expand All @@ -98,6 +114,10 @@
#define SIMDJSON_BUILTIN_IMPLEMENTATION arm64
#elif SIMDJSON_CAN_ALWAYS_RUN_PPC64
#define SIMDJSON_BUILTIN_IMPLEMENTATION ppc64
#elif SIMDJSON_CAN_ALWAYS_RUN_LSX
#define SIMDJSON_BUILTIN_IMPLEMENTATION lsx
#elif SIMDJSON_CAN_ALWAYS_RUN_LASX
#define SIMDJSON_BUILTIN_IMPLEMENTATION lasx
#elif SIMDJSON_CAN_ALWAYS_RUN_FALLBACK
#define SIMDJSON_BUILTIN_IMPLEMENTATION fallback
#else
Expand Down
4 changes: 3 additions & 1 deletion include/simdjson/internal/instruction_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ enum instruction_set {
AVX512CD = 0x2000,
AVX512BW = 0x4000,
AVX512VL = 0x8000,
AVX512VBMI2 = 0x10000
AVX512VBMI2 = 0x10000,
LSX = 0x20000,
LASX = 0x40000,
};

} // namespace internal
Expand Down
8 changes: 8 additions & 0 deletions include/simdjson/lasx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef SIMDJSON_LASX_H
#define SIMDJSON_LASX_H

#include "simdjson/lasx/begin.h"
#include "simdjson/generic/amalgamated.h"
#include "simdjson/lasx/end.h"

#endif // SIMDJSON_LASX_H
26 changes: 26 additions & 0 deletions include/simdjson/lasx/base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef SIMDJSON_LASX_BASE_H
#define SIMDJSON_LASX_BASE_H

#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE

namespace simdjson {
/**
* Implementation for LASX.
*/
namespace lasx {

class implementation;

namespace {
namespace simd {
template <typename T> struct simd8;
template <typename T> struct simd8x64;
} // namespace simd
} // unnamed namespace

} // namespace lasx
} // namespace simdjson

#endif // SIMDJSON_LASX_BASE_H
10 changes: 10 additions & 0 deletions include/simdjson/lasx/begin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#define SIMDJSON_IMPLEMENTATION lasx
#include "simdjson/lasx/base.h"
#include "simdjson/lasx/intrinsics.h"
#include "simdjson/lasx/bitmanipulation.h"
#include "simdjson/lasx/bitmask.h"
#include "simdjson/lasx/numberparsing_defs.h"
#include "simdjson/lasx/simd.h"
#include "simdjson/lasx/stringparsing_defs.h"

#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1
50 changes: 50 additions & 0 deletions include/simdjson/lasx/bitmanipulation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef SIMDJSON_LASX_BITMANIPULATION_H
#define SIMDJSON_LASX_BITMANIPULATION_H

#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/lasx/base.h"
#include "simdjson/lasx/intrinsics.h"
#include "simdjson/lasx/bitmask.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE

namespace simdjson {
namespace lasx {
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);
}

/* result might be undefined when input_num is zero */
simdjson_inline int count_ones(uint64_t input_num) {
return __lasx_xvpickve2gr_w(__lasx_xvpcnt_d(__m256i(v4u64{input_num, 0, 0, 0})), 0);
}

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 lasx
} // namespace simdjson

#endif // SIMDJSON_LASX_BITMANIPULATION_H
31 changes: 31 additions & 0 deletions include/simdjson/lasx/bitmask.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef SIMDJSON_LASX_BITMASK_H
#define SIMDJSON_LASX_BITMASK_H

#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/lasx/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE

namespace simdjson {
namespace lasx {
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) {
bitmask ^= bitmask << 1;
bitmask ^= bitmask << 2;
bitmask ^= bitmask << 4;
bitmask ^= bitmask << 8;
bitmask ^= bitmask << 16;
bitmask ^= bitmask << 32;
return bitmask;
}

} // unnamed namespace
} // namespace lasx
} // namespace simdjson

#endif
6 changes: 6 additions & 0 deletions include/simdjson/lasx/end.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/lasx/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE

#undef SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT
#undef SIMDJSON_IMPLEMENTATION
31 changes: 31 additions & 0 deletions include/simdjson/lasx/implementation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef SIMDJSON_LASX_IMPLEMENTATION_H
#define SIMDJSON_LASX_IMPLEMENTATION_H

#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/base.h"
#include "simdjson/implementation.h"
#include "simdjson/internal/instruction_set.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE

namespace simdjson {
namespace lasx {

/**
* @private
*/
class implementation final : public simdjson::implementation {
public:
simdjson_inline implementation() : simdjson::implementation("lasx", "LoongArch ASX", internal::instruction_set::LASX) {}
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 lasx
} // namespace simdjson

#endif // SIMDJSON_LASX_IMPLEMENTATION_H
14 changes: 14 additions & 0 deletions include/simdjson/lasx/intrinsics.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef SIMDJSON_LASX_INTRINSICS_H
#define SIMDJSON_LASX_INTRINSICS_H

#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/lasx/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE

// This should be the correct header whether
// you use visual studio or other compilers.
#include <lasxintrin.h>

static_assert(sizeof(__m256i) <= simdjson::SIMDJSON_PADDING, "insufficient padding for LoongArch ASX");

#endif // SIMDJSON_LASX_INTRINSICS_H
41 changes: 41 additions & 0 deletions include/simdjson/lasx/numberparsing_defs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#ifndef SIMDJSON_LASX_NUMBERPARSING_DEFS_H
#define SIMDJSON_LASX_NUMBERPARSING_DEFS_H

#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/lasx/base.h"
#include "simdjson/lasx/intrinsics.h"
#include "simdjson/internal/numberparsing_tables.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE

#include <cstring>

namespace simdjson {
namespace lasx {
namespace numberparsing {

// we don't have appropriate instructions, so let us use a scalar function
// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
/** @private */
static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
uint64_t val;
std::memcpy(&val, chars, sizeof(uint64_t));
val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
}

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 lasx
} // namespace simdjson

#define SIMDJSON_SWAR_NUMBER_PARSING 1

#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
8 changes: 8 additions & 0 deletions include/simdjson/lasx/ondemand.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef SIMDJSON_LASX_ONDEMAND_H
#define SIMDJSON_LASX_ONDEMAND_H

#include "simdjson/lasx/begin.h"
#include "simdjson/generic/ondemand/amalgamated.h"
#include "simdjson/lasx/end.h"

#endif // SIMDJSON_LASX_ONDEMAND_H