Skip to content

Commit

Permalink
Add LoongArch LSX and LASX support (#2159)
Browse files Browse the repository at this point in the history
* Add LoongArch SX support

* Add LoongArch ASX support
  • Loading branch information
MQ-mengqing committed Apr 4, 2024
1 parent 58e3d5d commit 4c98e51
Show file tree
Hide file tree
Showing 39 changed files with 1,670 additions and 6 deletions.
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

0 comments on commit 4c98e51

Please sign in to comment.