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
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,16 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64)")
PROPERTIES COMPILE_FLAGS "-mavx512f -mavx512bw -mavx512vl -mavx512dq -mavx512cd -mavx2 -mfma -mf16c")
endif()

if(__LOONGARCH64)
set_source_files_properties(
src/index/sparse/codec/varintdecode.c
src/index/sparse/codec/streamvbyte_0124_decode.c
src/index/sparse/codec/streamvbyte_0124_encode.c
src/index/sparse/codec/simd_bitpacking_kernel.c
src/index/sparse/sindi_simd_lsx.cc
PROPERTIES COMPILE_OPTIONS "-mlsx;-mno-lasx")
endif()

if(__AARCH64)
set(KNOWHERE_SVE_COMPILE_OPTIONS "")
if(HAS_ARMV9_SVE_BF16)
Expand Down
16 changes: 12 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ WITH_GPU ?=
WITH_UT ?=
WITH_BENCHMARK ?=
WITH_ASAN ?=
WITH_DISKANN ?= True
WITH_SVS ?=
WITH_CARDINAL ?=
CARDINAL_VERSION_FORCE_CHECKOUT ?=
Expand All @@ -40,7 +41,7 @@ export CMAKE_POLICY_VERSION_MINIMUM ?= 3.5
# variables such as WITH_ASAN to every sub-process, which causes the custom
# folly recipe to pick up $ENV{WITH_ASAN} and compile folly itself with
# -fsanitize=address — breaking the build on GCC.
unexport WITH_GPU WITH_UT WITH_BENCHMARK WITH_ASAN WITH_CARDINAL CARDINAL_VERSION_FORCE_CHECKOUT WITH_DEBUG
unexport WITH_GPU WITH_UT WITH_BENCHMARK WITH_ASAN WITH_DISKANN WITH_CARDINAL CARDINAL_VERSION_FORCE_CHECKOUT WITH_DEBUG

# ---------- Derived settings ----------
ifdef WITH_DEBUG
Expand All @@ -66,9 +67,15 @@ CONAN_SETTINGS := -s compiler.libcxx=$(LIBCXX) -s build_type=$(BUILD_TYPE) -s co

# DiskANN and liburing require libaio (Linux-only).
ifneq ($(UNAME_S),Darwin)
CONAN_SETTINGS += -o \&:with_diskann=True
ifndef WITH_GPU
CONAN_INSTALL_FLAGS += --build=liburing
ifneq ($(filter True true ON on 1,$(WITH_DISKANN)),)
CONAN_SETTINGS += -o \&:with_diskann=True
ifndef WITH_GPU
CONAN_INSTALL_FLAGS += --build=liburing
endif
else ifneq ($(filter False false OFF off 0,$(WITH_DISKANN)),)
CONAN_SETTINGS += -o \&:with_diskann=False
else
$(error WITH_DISKANN must be True/False, ON/OFF, or 1/0)
endif
endif

Expand Down Expand Up @@ -173,6 +180,7 @@ help: ## Show available targets
@echo " WITH_UT=True Enable unit tests"
@echo " WITH_BENCHMARK=True Enable benchmarks build"
@echo " WITH_ASAN=True Enable AddressSanitizer"
@echo " WITH_DISKANN=False Disable DiskANN (enabled by default on Linux)"
@echo " WITH_SVS=True Enable SVS (Intel Scalable Vector Search, x86 only)"
@echo " WITH_CARDINAL=True Enable Cardinal build"
@echo " CARDINAL_VERSION_FORCE_CHECKOUT=True Force Cardinal checkout to configured version"
Expand Down
38 changes: 38 additions & 0 deletions cmake/libs/libfaiss.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,22 @@ if(__RISCV64)
)
endif()

# generate `knowhere_utils` library for LoongArch64
if(__LOONGARCH64)
set(UTILS_SRC
src/simd/hook.cc
src/simd/distances_ref.cc)
add_library(utils_lsx OBJECT src/simd/distances_lsx.cc)
add_library(utils_lasx OBJECT src/simd/distances_lasx.cc)
target_compile_options(utils_lsx PRIVATE -mlsx -mno-lasx)
target_compile_options(utils_lasx PRIVATE -mlasx)

add_library(knowhere_utils STATIC ${UTILS_SRC} $<TARGET_OBJECTS:utils_lsx> $<TARGET_OBJECTS:utils_lasx>)
target_link_libraries(knowhere_utils PUBLIC glog::glog)
target_link_libraries(knowhere_utils PUBLIC xxHash::xxhash)
target_link_libraries(knowhere_utils PUBLIC milvus-common::milvus-common)
endif()

# generate `knowhere_utils` library for PPC64
# ToDo: Add distances_vsx.cc for powerpc64 SIMD acceleration
if(__PPC64)
Expand Down Expand Up @@ -576,6 +592,28 @@ if(__RISCV64)
target_compile_definitions(faiss PRIVATE FINTEGER=int COMPILE_SIMD_RISCV_RVV)
endif()

# generate `faiss` library for LoongArch64
if(__LOONGARCH64)
add_library(faiss STATIC ${FAISS_SRCS})
target_include_directories(faiss PRIVATE ${Boost_INCLUDE_DIRS})
target_sources(faiss PRIVATE ${FAISS_FASTSCAN_SRCS})

target_compile_options(
faiss
PRIVATE $<$<COMPILE_LANGUAGE:CXX>:
-Wno-sign-compare
-Wno-unused-variable
-Wno-reorder
-Wno-unused-local-typedefs
-Wno-unused-function
-Wno-strict-aliasing>)

add_dependencies(faiss knowhere_utils)
target_link_libraries(faiss PUBLIC OpenMP::OpenMP_CXX ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES}
knowhere_utils)
target_compile_definitions(faiss PRIVATE FINTEGER=int FAISS_ENABLE_DD)
endif()

# generate `faiss` library for PPC64
if(__PPC64)
add_library(faiss STATIC ${FAISS_SRCS})
Expand Down
7 changes: 7 additions & 0 deletions cmake/utils/compile_flags.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ if(__X86_64)
set(CMAKE_CXX_FLAGS "-msse4.2 ${CMAKE_CXX_FLAGS}")
endif()

# Keep LoongArch vector instructions confined to dedicated objects, which opt
# into LSX or LASX explicitly.
if(__LOONGARCH64)
set(CMAKE_C_FLAGS "-mno-lsx -mno-lasx ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "-mno-lsx -mno-lasx ${CMAKE_CXX_FLAGS}")
endif()

set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")

Expand Down
6 changes: 4 additions & 2 deletions cmake/utils/platform_check.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ macro(detect_target_arch)
check_symbol_exists(__x86_64__ "" __X86_64)
check_symbol_exists(__powerpc64__ "" __PPC64)
check_symbol_exists(__riscv "" __RISCV64)
check_symbol_exists(__loongarch64 "" __LOONGARCH64)

if(NOT __AARCH64
AND NOT __X86_64
AND NOT __PPC64
AND NOT __RISCV64)
message(FATAL "knowhere only support amd64, ppc64, riscv64 and arm64 architecture.")
AND NOT __RISCV64
AND NOT __LOONGARCH64)
message(FATAL "knowhere only supports amd64, arm64, loongarch64, ppc64 and riscv64 architectures.")
endif()
endmacro()

Expand Down
88 changes: 88 additions & 0 deletions src/index/sparse/codec/lsx_sse_compat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright (C) 2019-2023 Zilliz. All rights reserved.
//
// 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 <lsxintrin.h>
#include <stdint.h>

// The sparse codecs retain SSE intrinsics from their upstream implementations.
// Map only the operations they use so LoongArch builds execute native LSX.
static inline __m128i
knowhere_lsx_loadu_si128(const __m128i* ptr) {
return __lsx_vld((void*)ptr, 0);
}

static inline void
knowhere_lsx_storeu_si128(__m128i* ptr, __m128i value) {
__lsx_vst(value, ptr, 0);
}

static inline void
knowhere_lsx_storel_epi64(__m128i* ptr, __m128i value) {
__lsx_vstelm_d(value, ptr, 0, 0);
}

static inline int
knowhere_lsx_movemask_epi8(__m128i value) {
return (int)__lsx_vpickve2gr_hu(__lsx_vmskltz_b(value), 0);
}

static inline __m128i
knowhere_lsx_cvtepi8_epi32(__m128i value) {
typedef int8_t i8x4 __attribute__((vector_size(4)));
const i8x4 lower = __builtin_shufflevector((v16i8)value, (v16i8)value, 0, 1, 2, 3);
return (__m128i) __builtin_convertvector(lower, v4i32);
}

static inline __m128i
knowhere_lsx_shuffle_epi8(__m128i value, __m128i mask) {
const __m128i index = __lsx_vor_v(__lsx_vandi_b(mask, 0x0f), __lsx_vandi_b(__lsx_vslti_b(mask, 0), 0x10));
return __lsx_vshuf_b(__lsx_vldi(0), value, index);
}

static inline __m128i
knowhere_lsx_setr_epi16(int16_t e0, int16_t e1, int16_t e2, int16_t e3, int16_t e4, int16_t e5, int16_t e6,
int16_t e7) {
return (__m128i)(v8i16){e0, e1, e2, e3, e4, e5, e6, e7};
}

static inline __m128i
knowhere_lsx_setr_epi8(int8_t e0, int8_t e1, int8_t e2, int8_t e3, int8_t e4, int8_t e5, int8_t e6, int8_t e7,
int8_t e8, int8_t e9, int8_t e10, int8_t e11, int8_t e12, int8_t e13, int8_t e14, int8_t e15) {
return (__m128i)(v16i8){e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15};
}

#define _mm_and_si128(a, b) __lsx_vand_v((a), (b))
#define _mm_add_epi32(a, b) __lsx_vadd_w((a), (b))
#define _mm_cvtsi128_si32(a) __lsx_vpickve2gr_w((a), 0)
#define _mm_cvtepi8_epi32(a) knowhere_lsx_cvtepi8_epi32(a)
#define _mm_lddqu_si128(ptr) knowhere_lsx_loadu_si128(ptr)
#define _mm_loadu_si128(ptr) knowhere_lsx_loadu_si128(ptr)
#define _mm_movemask_epi8(a) knowhere_lsx_movemask_epi8(a)
#define _mm_mullo_epi16(a, b) __lsx_vmul_h((a), (b))
#define _mm_or_si128(a, b) __lsx_vor_v((a), (b))
#define _mm_set1_epi16(a) __lsx_vreplgr2vr_h(a)
#define _mm_set1_epi32(a) __lsx_vreplgr2vr_w(a)
#define _mm_set1_epi8(a) __lsx_vreplgr2vr_b(a)
#define _mm_setr_epi16(...) knowhere_lsx_setr_epi16(__VA_ARGS__)
#define _mm_setr_epi8(...) knowhere_lsx_setr_epi8(__VA_ARGS__)
#define _mm_shuffle_epi8(a, b) knowhere_lsx_shuffle_epi8((a), (b))
#define _mm_shuffle_epi32(a, imm) __lsx_vshuf4i_w((a), (imm))
#define _mm_slli_epi32(a, imm) __lsx_vslli_w((a), (imm))
#define _mm_slli_epi64(a, imm) __lsx_vslli_d((a), (imm))
#define _mm_slli_si128(a, imm) __lsx_vbsll_v((a), (imm))
#define _mm_srli_epi16(a, imm) __lsx_vsrli_h((a), (imm))
#define _mm_srli_epi32(a, imm) __lsx_vsrli_w((a), (imm))
#define _mm_srli_epi64(a, imm) __lsx_vsrli_d((a), (imm))
#define _mm_srli_si128(a, imm) __lsx_vbsrl_v((a), (imm))
#define _mm_storel_epi64(ptr, a) knowhere_lsx_storel_epi64((ptr), (a))
#define _mm_storeu_si128(ptr, a) knowhere_lsx_storeu_si128((ptr), (a))
2 changes: 2 additions & 0 deletions src/index/sparse/codec/simdcomp/include/portability.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "neon128.h"
#elif defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
#include <emmintrin.h>
#elif defined(__loongarch_sx)
#include "../../lsx_sse_compat.h"
#else
/* Keep the generated SSE2 kernels available on the other architectures supported by Knowhere. */
#ifndef SIMDE_ENABLE_NATIVE_ALIASES
Expand Down
35 changes: 28 additions & 7 deletions src/index/sparse/codec/streamvbyte_0124_decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
#include <stdint.h>
#include <string.h> // for memcpy

#if defined(__SSE4_1__) || defined(__ARM_NEON__) || defined(__ARM_NEON)
#if defined(__SSE4_1__) || defined(__ARM_NEON__) || defined(__ARM_NEON) || defined(__loongarch_sx)
#define KNOWHERE_STREAMVBYTE_SIMD
#endif

#ifdef KNOWHERE_STREAMVBYTE_SIMD
// using 0,1,2,4 bytes per value
static uint8_t lengthTable[256] = {
0, 1, 2, 4, 1, 2, 3, 5, 2, 3, 4, 6, 4, 5, 6, 8, 1, 2, 3, 5, 2, 3, 4, 6, 3, 4, 5, 7, 5, 6, 7, 9,
Expand Down Expand Up @@ -285,30 +289,47 @@ static int8_t shuffleTable[256][16] = {

#if defined(__SSE4_1__)
#include <immintrin.h>
#elif defined(__loongarch_sx)
#include <lsxintrin.h>
#elif defined(__ARM_NEON__) || defined(__ARM_NEON)
#include <arm_neon.h>
#endif

#ifdef __SSE4_1__
#if defined(__SSE4_1__) || defined(__loongarch_sx)
typedef __m128i decode_t;

static inline decode_t
svb_decode_uint32x4(const uint8_t key, const uint8_t* __restrict__* dataPtrPtr) {
uint8_t len = 0;
#if defined(__loongarch_sx)
decode_t Data = __lsx_vld((void*)*dataPtrPtr, 0);
decode_t Shuf = __lsx_vld((void*)&shuffleTable[key], 0);
#else
decode_t Data = _mm_loadu_si128((const decode_t*)*dataPtrPtr);
uint8_t* pshuf = (uint8_t*)&shuffleTable[key];
decode_t Shuf = *(__m128i*)pshuf;
#endif
len = lengthTable[key];
#if defined(__loongarch_sx)
// vshuf.b indexes its second input for indices 0..15 and its first
// input for 16..31. A table entry of -1 therefore selects a zero byte.
Data = __lsx_vshuf_b(__lsx_vldi(0), Data, Shuf);
#else
Data = _mm_shuffle_epi8(Data, Shuf);
#endif
*dataPtrPtr += len;
return Data;
}

static inline void
svb_write_uint32x4(uint32_t* out, decode_t Vec) {
#if defined(__loongarch_sx)
__lsx_vst(Vec, out, 0);
#else
_mm_storeu_si128((__m128i*)out, Vec);
#endif
}
#endif // __SSE4_1__
#endif // __SSE4_1__ || __loongarch_sx

#if defined(__ARM_NEON__) || defined(__ARM_NEON)
typedef uint8x16_t decode_t;
Expand Down Expand Up @@ -376,7 +397,7 @@ svb_decode_scalar(uint32_t* outPtr, const uint8_t* keyPtr, const uint8_t* dataPt
return dataPtr; // pointer to first unused byte after end
}

#if defined(__SSE4_1__) || defined(__ARM_NEON__) || defined(__ARM_NEON)
#ifdef KNOWHERE_STREAMVBYTE_SIMD
static const uint8_t*
svb_decode_vec128_simple(uint32_t* out, const uint8_t* __restrict__ keyPtr, const uint8_t* __restrict__ dataPtr,
uint64_t count) {
Expand Down Expand Up @@ -449,7 +470,7 @@ svb_decode_vec128_simple(uint32_t* out, const uint8_t* __restrict__ keyPtr, cons

return dataPtr;
}
#endif // __SSE4_1__ || __ARM_NEON__ || __ARM_NEON
#endif // KNOWHERE_STREAMVBYTE_SIMD

// Read count 32-bit integers in maskedvbyte format from in, storing the result
// in out. Returns the number of bytes read.
Expand All @@ -463,12 +484,12 @@ streamvbyte_decode_0124(const uint8_t* in, uint32_t* out, uint32_t count) {
uint32_t keyLen = ((count + 3) / 4); // 2-bits per key (rounded up)
const uint8_t* dataPtr = keyPtr + keyLen; // data starts at end of keys

#if defined(__SSE4_1__) || defined(__ARM_NEON__) || defined(__ARM_NEON)
#ifdef KNOWHERE_STREAMVBYTE_SIMD
dataPtr = svb_decode_vec128_simple(out, keyPtr, dataPtr, count);
out += count & ~31U;
keyPtr += (count / 4) & ~7U;
count &= 31;
#endif // __SSE4_1__ || __ARM_NEON__ || __ARM_NEON
#endif // KNOWHERE_STREAMVBYTE_SIMD

return (size_t)(svb_decode_scalar(out, keyPtr, dataPtr, count) - in);
}
Expand Down
Loading
Loading