Repository: numpy/numpy
Pull request: BUG: Fix build issues on SPR and avx512_qsort float16
Fixes https://github.com/numpy/numpy/issues/25274, https://github.com/numpy/numpy/issues/25382

1. Marks explicit template specializations in x86-simd-sort as inline. 
2. Adds CI to run tests on TGL and SPR platforms with latest version of Intel SDE v9.27. 
3. Bug fix in `avx512_qsort<float16>`, which was detected when enabling the CI on TGL. 

<!--         ----------------------------------------------------------------
                MAKE SURE YOUR PR GETS THE ATTENTION IT DESERVES!
                ----------------------------------------------------------------

*  FORMAT IT RIGHT:
      https://www.numpy.org/devdocs/dev/development_workflow.html#writing-the-commit-message

*  IF IT'S A NEW FEATURE OR API CHANGE, TEST THE WATERS:
      https://www.numpy.org/devdocs/dev/development_workflow.html#get-the-mailing-list-s-opinion

*  HIT ALL THE GUIDELINES:
      https://numpy.org/devdocs/dev/index.html#guidelines

*  WHAT TO DO IF WE HAVEN'T GOTTEN BACK TO YOU:
      https://www.numpy.org/devdocs/dev/development_workflow.html#getting-your-pr-reviewed
-->


Problem statement:
BUG: Build failure (of 1.26.2) on SapphireRapids (`avx512_spr`) due to multiple definition of `avx512_qsort` and `avx512_qselect`
### Describe the issue:

Building 1.26.2 on SapphireRapids with
```
spin build -- -Dcpu-baseline=native
```
or, on IceLake with
```
spin build -- -Dcpu-baseline=avx512_spr
```

Fails due to multiple definition of `void avx512_qsort<_Float16>(_Float16*, long)` and `void avx512_qselect<_Float16>(_Float16*, long, long)`.

### Reproduce the code example:

```python
n/a
```


### Error message:

```shell
FAILED: numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so                                                                                                                                          c++  -o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/meson-generated_arraytypes.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/meson-generated_einsum.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/meson-generated_einsum_sumprod.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/meson-generated_lowlevel_strided_loops.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/meson-generated_nditer_templ.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/meson-generated_scalartypes.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/meson-generated_loops.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/meson-generated_matmul.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/meson-generated_scalarmath.c.o ../numpy/core/src/umath/svml/linux/avx512/svml_z0_acos_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_acos_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_acos_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_acosh_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_acosh_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_acosh_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_asin_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_asin_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_asin_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_asinh_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_asinh_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_asinh_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_atan2_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_atan2_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_atan2_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_atan_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_atan_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_atan_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_atanh_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_atanh_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_atanh_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_cbrt_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_cbrt_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_cbrt_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_cos_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_cos_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_cos_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_cosh_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_cosh_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_cosh_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_exp2_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_exp2_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_exp2_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_exp_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_exp_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_exp_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_expm1_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_expm1_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_expm1_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_log10_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_log10_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_log10_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_log1p_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_log1p_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_log1p_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_log2_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_log2_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_log2_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_log_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_log_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_log_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_pow_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_pow_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_pow_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_sin_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_sin_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_sin_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_sinh_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_sinh_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_sinh_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_tan_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_tan_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_tan_d_ha.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_tanh_d_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_tanh_s_la.s ../numpy/core/src/umath/svml/linux/avx512/svml_z0_tanh_d_ha.s numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_abstractdtypes.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_alloc.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_arrayobject.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_array_coercion.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_array_method.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_array_assign_scalar.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_array_assign_array.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_arrayfunction_override.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_buffer.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_calculation.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_compiled_base.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_common.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_common_dtype.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_convert.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_convert_datatype.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_conversion_utils.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_ctors.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_datetime.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_datetime_strings.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_datetime_busday.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_datetime_busdaycal.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_descriptor.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_dlpack.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_dtypemeta.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_dragon4.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_dtype_transfer.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_dtype_traversal.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_experimental_public_dtype_api.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_flagsobject.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_getset.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_hashdescr.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_item_selection.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_iterators.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_legacy_dtype_implementation.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_mapping.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_methods.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_multiarraymodule.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_nditer_api.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_nditer_constr.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_nditer_pywrap.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_number.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_refcount.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_sequence.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_shape.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_scalarapi.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_strfuncs.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_temp_elide.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_typeinfo.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_usertypes.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_vdot.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_npysort_quicksort.cpp.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_npysort_mergesort.cpp.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_npysort_timsort.cpp.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_npysort_heapsort.cpp.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_npysort_radixsort.cpp.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_npysort_selection.cpp.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_npysort_binsearch.cpp.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_textreading_conversions.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_textreading_field_types.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_textreading_growth.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_textreading_readtext.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_textreading_rows.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_textreading_stream_pyobject.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_textreading_str_to_int.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_multiarray_textreading_tokenize.cpp.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_npymath_arm64_exports.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_common_array_assign.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_common_mem_overlap.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_common_npy_argparse.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_common_npy_hashtable.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_common_npy_longdouble.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_common_ucsnarrow.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_common_ufunc_override.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_common_numpyos.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_common_npy_cpu_features.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_common_cblasfuncs.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_common_python_xerbla.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_umath_ufunc_type_resolution.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_umath_clip.cpp.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_umath_dispatching.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_umath_extobj.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_umath_legacy_array_method.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_umath_override.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_umath_reduction.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_umath_ufunc_object.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_umath_umathmodule.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_umath_string_ufuncs.cpp.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_umath_wrapping_array_method.c.o numpy/core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so.p/src_umath__scaled_float_dtype.c.o -Wl,--as-needed -Wl,--allow-shlib-undefined -shared -fPIC -Wl,--start-group numpy/core/libnpymath.a numpy/core/lib_multiarray_umath_mtargets.a /rds/projects/2017/branfosj-rse/easybuild/EL8-ice/software/OpenBLAS/0.3.24-GCC-13.2.0/lib/libopenblas.so -Wl,--end-group
/rds/projects/2017/branfosj-rse/easybuild/EL8-ice/software/binutils/2.40-GCCcore-13.2.0/bin/ld: numpy/core/libsimd_qsort_16bit.dispatch.h_AVX512_SPR.a.p/src_npysort_simd_qsort_16bit.dispatch.cpp.o: in function `void avx512_qsort<_Float16>(_Float16*, long)':
/rds/projects/2017/branfosj-rse/ProblemSolving/numpy/numpy-1.26.2/build/../numpy/core/src/npysort/x86-simd-sort/src/avx512fp16-16bit-qsort.hpp:161: multiple definition of `void avx512_qsort<_Float16>(_Float16*, long)'; numpy/core/libsimd_qsort_16bit.dispatch.h_AVX512_ICL.a.p/src_npysort_simd_qsort_16bit.dispatch.cpp.o:/rds/projects/2017/branfosj-rse/ProblemSolving/numpy/numpy-1.26.2/build/../numpy/core/src/npysort/x86-simd-sort/src/avx512fp16-16bit-qsort.hpp:161: first defined here
/rds/projects/2017/branfosj-rse/easybuild/EL8-ice/software/binutils/2.40-GCCcore-13.2.0/bin/ld: numpy/core/libsimd_qsort_16bit.dispatch.h_AVX512_SPR.a.p/src_npysort_simd_qsort_16bit.dispatch.cpp.o: in function `void avx512_qselect<_Float16>(_Float16*, long, long)':
/rds/projects/2017/branfosj-rse/ProblemSolving/numpy/numpy-1.26.2/build/../numpy/core/src/npysort/x86-simd-sort/src/avx512fp16-16bit-qsort.hpp:149: multiple definition of `void avx512_qselect<_Float16>(_Float16*, long, long)'; numpy/core/libsimd_qsort_16bit.dispatch.h_AVX512_ICL.a.p/src_npysort_simd_qsort_16bit.dispatch.cpp.o:/rds/projects/2017/branfosj-rse/ProblemSolving/numpy/numpy-1.26.2/build/../numpy/core/src/npysort/x86-simd-sort/src/avx512fp16-16bit-qsort.hpp:149: first defined here
collect2: error: ld returned 1 exit status
```


### Runtime information:

```
The Meson build system 
Version: 1.2.99
Source dir: /rds/projects/2017/branfosj-rse/ProblemSolving/numpy/numpy-1.26.2
Build dir: /rds/projects/2017/branfosj-rse/ProblemSolving/numpy/numpy-1.26.2/build
Build type: native build
Project name: NumPy
Project version: 1.26.2
C compiler for the host machine: cc (gcc 13.2.0 "cc (GCC) 13.2.0")
C linker for the host machine: cc ld.bfd 2.40
C++ compiler for the host machine: c++ (gcc 13.2.0 "c++ (GCC) 13.2.0")
C++ linker for the host machine: c++ ld.bfd 2.40
Cython compiler for the host machine: cython (cython 3.0.4)
Host machine cpu family: x86_64
Host machine cpu: x86_64
Program python3 found: YES (/rds/projects/2017/branfosj-rse/easybuild/EL8-ice/software/Python/3.11.5-GCCcore-13.2.0/bin/python)
Found pkg-config: /rds/projects/2017/branfosj-rse/easybuild/EL8-ice/software/pkgconf/2.0.3-GCCcore-13.2.0/bin/pkg-config (2.0.3)
Run-time dependency python found: YES 3.11
Has header "Python.h" with dependency python-3.11: YES
Compiler for C supports arguments -fno-strict-aliasing: YES
Test features "SSE SSE2 SSE3 SSSE3 SSE41 POPCNT SSE42 AVX F16C FMA3 AVX2 AVX512F AVX512CD AVX512_SKX AVX512_CLX AVX512_CNL AVX512_ICL AVX512_SPR" : Supported
Test features "AVX512_KNL" : Supported
Test features "AVX512_KNM" : Supported
Configuring npy_cpu_dispatch_config.h using configuration
Message:
     CPU Optimization Options
baseline:
        Requested : avx512_spr
		Enabled   : SSE SSE2 SSE3 SSSE3 SSE41 POPCNT SSE42 AVX F16C FMA3 AVX2 AVX512F AVX512CD AVX512_SKX AVX512_CLX AVX512_CNL AVX512_ICL AVX512_SPR
dispatch:
        Requested : max -xop -fma4
		Enabled   : AVX512_KNL AVX512_KNM
Library m found: YES
Run-time dependency scipy-openblas found: NO (tried pkgconfig)
Run-time dependency mkl found: NO (tried pkgconfig and system)
Run-time dependency mkl found: NO (tried pkgconfig and system)
Run-time dependency accelerate found: NO (tried system)
Run-time dependency openblas found: YES 0.3.24
Message: BLAS symbol suffix:
Run-time dependency mkl found: NO (tried pkgconfig and system)
Run-time dependency accelerate found: NO (tried system)
Run-time dependency openblas found: YES 0.3.24
```

And the last part of the configure
```
 Generating multi-targets for "_umath_tests.dispatch.h"                                                                                                                                                          Enabled targets: baseline                                                                                                                                                                                   Generating multi-targets for "argfunc.dispatch.h"                                                                                                                                                               Enabled targets: baseline                                                                                                                                                                                   Generating multi-targets for "simd_qsort.dispatch.h"                                                                                                                                                            Enabled targets: AVX512_SKX                                                                                                                                                                                 Generating multi-targets for "simd_qsort_16bit.dispatch.h"                                                                                                                                                      Enabled targets: AVX512_SPR, AVX512_ICL                                                                                                                                                                     Generating multi-targets for "loops_arithm_fp.dispatch.h"                                                                                                                                                       Enabled targets: baseline                                                                                                                                                                                   Generating multi-targets for "loops_arithmetic.dispatch.h"                                                                                                                                                      Enabled targets: baseline                                                                                                                                                                                   Generating multi-targets for "loops_comparison.dispatch.h"                                                                                                                                                      Enabled targets: baseline
Generating multi-targets for "loops_exponent_log.dispatch.h"                                                                                                                                                    Enabled targets: baseline
Generating multi-targets for "loops_hyperbolic.dispatch.h"                                                                                                                                                      Enabled targets: baseline                                                                                                                                                                                   Generating multi-targets for "loops_logical.dispatch.h"
  Enabled targets: baseline                                                                                                                                                                                   Generating multi-targets for "loops_minmax.dispatch.h"
  Enabled targets: baseline                                                                                                                                                                                   Generating multi-targets for "loops_modulo.dispatch.h"                                                                                                                                                          Enabled targets: baseline
Generating multi-targets for "loops_trigonometric.dispatch.h"
  Enabled targets: baseline
Generating multi-targets for "loops_umath_fp.dispatch.h"
  Enabled targets: baseline
Generating multi-targets for "loops_unary.dispatch.h"
  Enabled targets: baseline
Generating multi-targets for "loops_unary_fp.dispatch.h"
  Enabled targets: baseline
Generating multi-targets for "loops_unary_fp_le.dispatch.h"
  Enabled targets: baseline
Generating multi-targets for "loops_unary_complex.dispatch.h"
  Enabled targets: baseline
Generating multi-targets for "loops_autovec.dispatch.h"
  Enabled targets: baseline
Generating multi-targets for "_simd.dispatch.h"
  Enabled targets: baseline
Build targets in project: 62

NumPy 1.26.2

  User defined options
    prefix      : /usr
    cpu-baseline: avx512_spr
```

### Context for the issue:

_No response_

Hints from issue discussion:
@branfosj thanks for reporting. I am taking a look.
This looks like a bug in the build system. The issue seems to be that `qsort_16bit dispatch` file is built with baseline cpu flags on top of the specific dispatch flags which, if I understand correctly, is not intended. When using `-Dcpu-baseline=avx512_spr`, the `avx512_icl `dispatch essentially gets built with `avx512_spr` leading to multiple definition error. See commands used to build the `x86_simd_qsort_16bit.dispatch.cpp` file below: 

```
{
    "directory": "/home/raghuveer/MyFiles/src/wrkdir_numpy/numpy/build",
    "command": "g++-12 -Inumpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_SPR.a.p -Inumpy/_core -I../numpy/_core -Inumpy/_core/include -I../numpy/_core/include -I../numpy/_core/src/common -I../numpy/_core/src/multiarray -I../numpy/_core/src/npymath -I../numpy/_core/src/umath -I../numpy/_core/src/highway -I/home/raghuveer/anaconda3/envs/np-dev/include/python3.11 -I/home/raghuveer/MyFiles/src/wrkdir_numpy/numpy/build/meson_cpu -fdiagnostics-color=always -Wall -Winvalid-pch -std=c++17 -O2 -g -msse -msse2 -msse3 -mssse3 -msse4.1 -mpopcnt -msse4.2 -mavx -mf16c -mfma -mavx2 -mno-mmx -mavx512f -mavx512cd -mavx512vl -mavx512bw -mavx512dq -mavx512vnni -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx512bitalg -mavx512vpopcntdq -mavx512fp16 -fPIC -DNPY_INTERNAL_BUILD -DHAVE_NPY_CONFIG_H -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -D__STDC_VERSION__=0 -fno-exceptions -fno-rtti -O3 -DNPY_HAVE_SSE2 -DNPY_HAVE_SSE -DNPY_HAVE_SSE3 -DNPY_HAVE_SSSE3 -DNPY_HAVE_SSE41 -DNPY_HAVE_POPCNT -DNPY_HAVE_SSE42 -DNPY_HAVE_AVX -DNPY_HAVE_F16C -DNPY_HAVE_FMA3 -DNPY_HAVE_AVX2 -DNPY_HAVE_AVX512F -DNPY_HAVE_AVX512F_REDUCE -DNPY_HAVE_AVX512CD -DNPY_HAVE_AVX512_SKX -DNPY_HAVE_AVX512VL -DNPY_HAVE_AVX512BW -DNPY_HAVE_AVX512DQ -DNPY_HAVE_AVX512BW_MASK -DNPY_HAVE_AVX512DQ_MASK -DNPY_HAVE_AVX512_CLX -DNPY_HAVE_AVX512VNNI -DNPY_HAVE_AVX512_CNL -DNPY_HAVE_AVX512IFMA -DNPY_HAVE_AVX512VBMI -DNPY_HAVE_AVX512_ICL -DNPY_HAVE_AVX512VBMI2 -DNPY_HAVE_AVX512BITALG -DNPY_HAVE_AVX512VPOPCNTDQ -DNPY_HAVE_AVX512_SPR -DNPY_HAVE_AVX512FP16 -msse -msse2 -msse3 -mssse3 -msse4.1 -mpopcnt -msse4.2 -mavx -mf16c -mfma -mavx2 -mno-mmx -mavx512f -mavx512cd -mavx512vl -mavx512bw -mavx512dq -mavx512vnni -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx512bitalg -mavx512vpopcntdq -mavx512fp16 -DNPY_MTARGETS_CURRENT=AVX512_SPR -MD -MQ numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_SPR.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o -MF numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_SPR.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o.d -o numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_SPR.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o -c ../numpy/_core/src/npysort/x86_simd_qsort_16bit.dispatch.cpp",
    "file": "../numpy/_core/src/npysort/x86_simd_qsort_16bit.dispatch.cpp",
    "output": "numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_SPR.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o"
  },
  {
    "directory": "/home/raghuveer/MyFiles/src/wrkdir_numpy/numpy/build",
    "command": "g++-12 -Inumpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_ICL.a.p -Inumpy/_core -I../numpy/_core -Inumpy/_core/include -I../numpy/_core/include -I../numpy/_core/src/common -I../numpy/_core/src/multiarray -I../numpy/_core/src/npymath -I../numpy/_core/src/umath -I../numpy/_core/src/highway -I/home/raghuveer/anaconda3/envs/np-dev/include/python3.11 -I/home/raghuveer/MyFiles/src/wrkdir_numpy/numpy/build/meson_cpu -fdiagnostics-color=always -Wall -Winvalid-pch -std=c++17 -O2 -g -msse -msse2 -msse3 -mssse3 -msse4.1 -mpopcnt -msse4.2 -mavx -mf16c -mfma -mavx2 -mno-mmx -mavx512f -mavx512cd -mavx512vl -mavx512bw -mavx512dq -mavx512vnni -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx512bitalg -mavx512vpopcntdq -mavx512fp16 -DNPY_HAVE_AVX512_SPR -DNPY_HAVE_AVX512FP16 -fPIC -DNPY_INTERNAL_BUILD -DHAVE_NPY_CONFIG_H -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -D__STDC_VERSION__=0 -fno-exceptions -fno-rtti -O3 -DNPY_HAVE_SSE2 -DNPY_HAVE_SSE -DNPY_HAVE_SSE3 -DNPY_HAVE_SSSE3 -DNPY_HAVE_SSE41 -DNPY_HAVE_POPCNT -DNPY_HAVE_SSE42 -DNPY_HAVE_AVX -DNPY_HAVE_F16C -DNPY_HAVE_FMA3 -DNPY_HAVE_AVX2 -DNPY_HAVE_AVX512F -DNPY_HAVE_AVX512F_REDUCE -DNPY_HAVE_AVX512CD -DNPY_HAVE_AVX512_SKX -DNPY_HAVE_AVX512VL -DNPY_HAVE_AVX512BW -DNPY_HAVE_AVX512DQ -DNPY_HAVE_AVX512BW_MASK -DNPY_HAVE_AVX512DQ_MASK -DNPY_HAVE_AVX512_CLX -DNPY_HAVE_AVX512VNNI -DNPY_HAVE_AVX512_CNL -DNPY_HAVE_AVX512IFMA -DNPY_HAVE_AVX512VBMI -DNPY_HAVE_AVX512_ICL -DNPY_HAVE_AVX512VBMI2 -DNPY_HAVE_AVX512BITALG -DNPY_HAVE_AVX512VPOPCNTDQ -msse -msse2 -msse3 -mssse3 -msse4.1 -mpopcnt -msse4.2 -mavx -mf16c -mfma -mavx2 -mno-mmx -mavx512f -mavx512cd -mavx512vl -mavx512bw -mavx512dq -mavx512vnni -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx512bitalg -mavx512vpopcntdq -DNPY_MTARGETS_CURRENT=AVX512_ICL -MD -MQ numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_ICL.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o -MF numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_ICL.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o.d -o numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_ICL.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o -c ../numpy/_core/src/npysort/x86_simd_qsort_16bit.dispatch.cpp",
    "file": "../numpy/_core/src/npysort/x86_simd_qsort_16bit.dispatch.cpp",
    "output": "numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_ICL.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o"
  },

```

ping @seiko2plus 
~See also SapphireRapids and IceLake sorting concerns on `main` reproduced at: https://github.com/numpy/numpy/issues/24842#issuecomment-1850592759. Not sure if related though.~
> This looks like a bug in the build system. The issue seems to be that `qsort_16bit dispatch` file is built with baseline cpu flags on top of the specific dispatch flags which, if I understand correctly, is not intended. When using `-Dcpu-baseline=avx512_spr`, the `avx512_icl `dispatch essentially gets built with `avx512_spr` leading to multiple definition error. See commands used to build the `x86_simd_qsort_16bit.dispatch.cpp` file below:
> 
> ```
> {
>     "directory": "/home/raghuveer/MyFiles/src/wrkdir_numpy/numpy/build",
>     "command": "g++-12 -Inumpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_SPR.a.p -Inumpy/_core -I../numpy/_core -Inumpy/_core/include -I../numpy/_core/include -I../numpy/_core/src/common -I../numpy/_core/src/multiarray -I../numpy/_core/src/npymath -I../numpy/_core/src/umath -I../numpy/_core/src/highway -I/home/raghuveer/anaconda3/envs/np-dev/include/python3.11 -I/home/raghuveer/MyFiles/src/wrkdir_numpy/numpy/build/meson_cpu -fdiagnostics-color=always -Wall -Winvalid-pch -std=c++17 -O2 -g -msse -msse2 -msse3 -mssse3 -msse4.1 -mpopcnt -msse4.2 -mavx -mf16c -mfma -mavx2 -mno-mmx -mavx512f -mavx512cd -mavx512vl -mavx512bw -mavx512dq -mavx512vnni -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx512bitalg -mavx512vpopcntdq -mavx512fp16 -fPIC -DNPY_INTERNAL_BUILD -DHAVE_NPY_CONFIG_H -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -D__STDC_VERSION__=0 -fno-exceptions -fno-rtti -O3 -DNPY_HAVE_SSE2 -DNPY_HAVE_SSE -DNPY_HAVE_SSE3 -DNPY_HAVE_SSSE3 -DNPY_HAVE_SSE41 -DNPY_HAVE_POPCNT -DNPY_HAVE_SSE42 -DNPY_HAVE_AVX -DNPY_HAVE_F16C -DNPY_HAVE_FMA3 -DNPY_HAVE_AVX2 -DNPY_HAVE_AVX512F -DNPY_HAVE_AVX512F_REDUCE -DNPY_HAVE_AVX512CD -DNPY_HAVE_AVX512_SKX -DNPY_HAVE_AVX512VL -DNPY_HAVE_AVX512BW -DNPY_HAVE_AVX512DQ -DNPY_HAVE_AVX512BW_MASK -DNPY_HAVE_AVX512DQ_MASK -DNPY_HAVE_AVX512_CLX -DNPY_HAVE_AVX512VNNI -DNPY_HAVE_AVX512_CNL -DNPY_HAVE_AVX512IFMA -DNPY_HAVE_AVX512VBMI -DNPY_HAVE_AVX512_ICL -DNPY_HAVE_AVX512VBMI2 -DNPY_HAVE_AVX512BITALG -DNPY_HAVE_AVX512VPOPCNTDQ -DNPY_HAVE_AVX512_SPR -DNPY_HAVE_AVX512FP16 -msse -msse2 -msse3 -mssse3 -msse4.1 -mpopcnt -msse4.2 -mavx -mf16c -mfma -mavx2 -mno-mmx -mavx512f -mavx512cd -mavx512vl -mavx512bw -mavx512dq -mavx512vnni -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx512bitalg -mavx512vpopcntdq -mavx512fp16 -DNPY_MTARGETS_CURRENT=AVX512_SPR -MD -MQ numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_SPR.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o -MF numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_SPR.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o.d -o numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_SPR.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o -c ../numpy/_core/src/npysort/x86_simd_qsort_16bit.dispatch.cpp",
>     "file": "../numpy/_core/src/npysort/x86_simd_qsort_16bit.dispatch.cpp",
>     "output": "numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_SPR.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o"
>   },
>   {
>     "directory": "/home/raghuveer/MyFiles/src/wrkdir_numpy/numpy/build",
>     "command": "g++-12 -Inumpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_ICL.a.p -Inumpy/_core -I../numpy/_core -Inumpy/_core/include -I../numpy/_core/include -I../numpy/_core/src/common -I../numpy/_core/src/multiarray -I../numpy/_core/src/npymath -I../numpy/_core/src/umath -I../numpy/_core/src/highway -I/home/raghuveer/anaconda3/envs/np-dev/include/python3.11 -I/home/raghuveer/MyFiles/src/wrkdir_numpy/numpy/build/meson_cpu -fdiagnostics-color=always -Wall -Winvalid-pch -std=c++17 -O2 -g -msse -msse2 -msse3 -mssse3 -msse4.1 -mpopcnt -msse4.2 -mavx -mf16c -mfma -mavx2 -mno-mmx -mavx512f -mavx512cd -mavx512vl -mavx512bw -mavx512dq -mavx512vnni -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx512bitalg -mavx512vpopcntdq -mavx512fp16 -DNPY_HAVE_AVX512_SPR -DNPY_HAVE_AVX512FP16 -fPIC -DNPY_INTERNAL_BUILD -DHAVE_NPY_CONFIG_H -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -D__STDC_VERSION__=0 -fno-exceptions -fno-rtti -O3 -DNPY_HAVE_SSE2 -DNPY_HAVE_SSE -DNPY_HAVE_SSE3 -DNPY_HAVE_SSSE3 -DNPY_HAVE_SSE41 -DNPY_HAVE_POPCNT -DNPY_HAVE_SSE42 -DNPY_HAVE_AVX -DNPY_HAVE_F16C -DNPY_HAVE_FMA3 -DNPY_HAVE_AVX2 -DNPY_HAVE_AVX512F -DNPY_HAVE_AVX512F_REDUCE -DNPY_HAVE_AVX512CD -DNPY_HAVE_AVX512_SKX -DNPY_HAVE_AVX512VL -DNPY_HAVE_AVX512BW -DNPY_HAVE_AVX512DQ -DNPY_HAVE_AVX512BW_MASK -DNPY_HAVE_AVX512DQ_MASK -DNPY_HAVE_AVX512_CLX -DNPY_HAVE_AVX512VNNI -DNPY_HAVE_AVX512_CNL -DNPY_HAVE_AVX512IFMA -DNPY_HAVE_AVX512VBMI -DNPY_HAVE_AVX512_ICL -DNPY_HAVE_AVX512VBMI2 -DNPY_HAVE_AVX512BITALG -DNPY_HAVE_AVX512VPOPCNTDQ -msse -msse2 -msse3 -mssse3 -msse4.1 -mpopcnt -msse4.2 -mavx -mf16c -mfma -mavx2 -mno-mmx -mavx512f -mavx512cd -mavx512vl -mavx512bw -mavx512dq -mavx512vnni -mavx512ifma -mavx512vbmi -mavx512vbmi2 -mavx512bitalg -mavx512vpopcntdq -DNPY_MTARGETS_CURRENT=AVX512_ICL -MD -MQ numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_ICL.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o -MF numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_ICL.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o.d -o numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_ICL.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o -c ../numpy/_core/src/npysort/x86_simd_qsort_16bit.dispatch.cpp",
>     "file": "../numpy/_core/src/npysort/x86_simd_qsort_16bit.dispatch.cpp",
>     "output": "numpy/_core/libx86_simd_qsort_16bit.dispatch.h_AVX512_ICL.a.p/src_npysort_x86_simd_qsort_16bit.dispatch.cpp.o"
>   },
> ```


The behavior observed is not a bug but a consequence of defining a non-inline function in the C++ header files by `x86_simd_qsort_`, leading to a violation of the One Definition Rule (ODR). To resolve this, functions like qsort or any other non-inline functions should either be declared inline, which treats the function as a weak symbol and allows multiple definitions across translation units, or they should be defined within an anonymous namespace. The anonymous namespace approach ensures that each translation unit has its own unique version of the function, effectively preventing ODR violations while maintaining encapsulation.

@seiko2plus  I concluded the same in https://github.com/intel/x86-simd-sort/issues/111#issuecomment-1851553552

TLDR: Indeed an `inline` fixes the double symbol. However I fear it is numpy violating the ODR:
- "inline" allows the symbol to be defined by multiple TUs with the linker taking any of them assuming all are the same (code)
- template functions are "inline" by default
- numpy compiles the same file, with the same includes multiple times with different AVX flags
- generated code of those inline functions is now different (e.g. function is compiled with AVX2 and AVX512 in 2 cpp files)
- linking those object files together discards all but 1 of those inline function instances -> You'll end up with only AVX2 or AVX512 (or their sub-variants) as a single function
- dispatching now (likely, haven't fully investigated how the numpy dispatching works) will dispatch to a supposedly AVX2 function but the linker might have chosen the AVX512 function -> crash at runtime on CPUs not supporting AVX512

Having all functions have internal linkage fix that
- many functions in x86-simd-sort are even defined as `static inline` which is similar to the anonymous namespace
- Trouble: `static inline` cannot be applied to this template specialization, so the anonymous namespace needs to be used causing this to be required at more places
- numpy includes x86-simd-sort so all functions in x86-simd-sort need to have internal linkage which pessimizes all other users of the latter because under "normal circumstances" `inline` would be enough but now there'll be multiple copies of the function in a binary even though one would have been enough

And finally I think in both numpy and x86-simd-sort the use of templates and explicit specializations is overused or even misused. A common patter seems to be:

```
template <typename T>
void foo(T *arr, int64_t arrsize);
template <>
void foo(int16_t *arr, int64_t arrsize) { /* impl */ }
template <>
void foo(uint16_t *arr, int64_t arrsize) { /* impl */ }
// ...
```

Why are those templates and not simply overloaded functions? That would make e.g. the above addition of `static` for internal linkage much easier
#25376 should fix this build issue. Could you please verify? 
I checked out the PR locally and did a `pip install .` in an environment where it failed before and it does succeed with that PR.

However I still think this is an ODR violation from numpy in linking together functions compiled with different architecture flags which may lead to runtime crashes depending on the linker and target environment/cpu
> numpy compiles the same file, with the same includes multiple times with different AVX flags

That's true, but each compilation exports symbols with unique suffixes based on compiler # definition e.g. `-DNPY_MTARGETS_CURRENT=AVX512_ICL`

> generated code of those inline functions is now different (e.g. function is compiled with AVX2 and AVX512 in 2 cpp files)
> dispatching now (likely, haven't fully investigated how the numpy dispatching works) will dispatch to a supposedly AVX2 function but the linker might have chosen the AVX512 function -> crash at runtime on CPUs not supporting AVX512

If the compiler fails to inline a function then the priority goes to the lowest interest target that's why we tend to export unique weak symbols for each TPU, see https://github.com/numpy/numpy/pull/25045#discussion_r1412599183 for more clearfiction.

> And finally I think in both numpy and x86-simd-sort the use of templates and explicit specializations is overused or even misused. A common patter seems to be:

Both `Numpy` and `x86-simd-sort` use suffixed functions for SIMD kernels on both C and C++ sources to avoid ODR violation. 
But the suffixing is not exhaustive as can be seen by this issue: `avx512_qsort` is called from a file compiled with `-mavx512fp16` and again from a file without that as shown in https://github.com/numpy/numpy/issues/25274#issuecomment-1850630049. It might be possible that this function and all possibly called functions are not fully inlined into the TU

This applies similar to most functions in `x86-simd-sort` which are templates that are only "inline", i.e. weak symbols and not unique (which would require `static` or anonymous namespaces). So this heavily relies on the linker to hopefully sort it out correctly.

Commit message: CI: Split CI jobs on TGL and SPR

Patch to review:
diff --git a/.github/workflows/linux_simd.yml b/.github/workflows/linux_simd.yml
index 0b8f082b5494..bbad7090b14f 100644
--- a/.github/workflows/linux_simd.yml
+++ b/.github/workflows/linux_simd.yml
@@ -148,7 +148,7 @@ jobs:
     - uses: ./.github/meson_actions
       name: Build/Test
 
-  intel_sde:
+  intel_sde_avx512:
     needs: [baseline_only]
     runs-on: ubuntu-latest
     steps:
@@ -162,7 +162,7 @@ jobs:
 
     - name: Install Intel SDE
       run: |
-        curl -o /tmp/sde.tar.xz https://downloadmirror.intel.com/784319/sde-external-9.24.0-2023-07-13-lin.tar.xz
+        curl -o /tmp/sde.tar.xz https://downloadmirror.intel.com/788820/sde-external-9.27.0-2023-09-13-lin.tar.xz
         mkdir /tmp/sde && tar -xvf /tmp/sde.tar.xz -C /tmp/sde/
         sudo mv /tmp/sde/* /opt/sde && sudo ln -s /opt/sde/sde64 /usr/bin/sde
 
@@ -198,15 +198,59 @@ jobs:
         sde -spr -- python -c "import numpy; numpy.show_config()" &&
         sde -spr -- python -m pytest $NUMPY_SITE/numpy/_core/tests/test_simd*
 
-    # Can't run on SDE just yet: see https://github.com/numpy/numpy/issues/23545#issuecomment-1659047365
-    #
-    #- name: linalg/ufunc/umath tests (SPR)
-    #  run: |
-    #    export NUMPY_SITE=$(realpath build-install/usr/lib/python*/site-packages/)
-    #    export PYTHONPATH="$PYTHONPATH:$NUMPY_SITE"
-    #    cd build-install &&
-    #    sde -spr -- python -c "import numpy; numpy.show_config()" &&
-    #    sde -spr -- python -m pytest $NUMPY_SITE/numpy/_core/tests/test_umath* \
-    #                                 $NUMPY_SITE/numpy/_core/tests/test_ufunc.py \
-    #                                 $NUMPY_SITE/numpy/linalg/tests/test_*
+    - name: linalg/ufunc/umath tests (TGL)
+      run: |
+        export NUMPY_SITE=$(realpath build-install/usr/lib/python*/site-packages/)
+        export PYTHONPATH="$PYTHONPATH:$NUMPY_SITE"
+        cd build-install &&
+        sde -tgl -- python -c "import numpy; numpy.show_config()" &&
+        sde -tgl -- python -m pytest $NUMPY_SITE/numpy/_core/tests/test_umath* \
+                                     $NUMPY_SITE/numpy/_core/tests/test_ufunc.py \
+                                     $NUMPY_SITE/numpy/_core/tests/test_multiarray.py \
+                                     $NUMPY_SITE/numpy/linalg/tests/test_*
+
+
+  intel_sde_spr:
+    needs: [baseline_only]
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+      with:
+        submodules: recursive
+        fetch-depth: 0
+    - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
+      with:
+        python-version: '3.11'
+
+    - name: Install Intel SDE
+      run: |
+        curl -o /tmp/sde.tar.xz https://downloadmirror.intel.com/788820/sde-external-9.27.0-2023-09-13-lin.tar.xz
+        mkdir /tmp/sde && tar -xvf /tmp/sde.tar.xz -C /tmp/sde/
+        sudo mv /tmp/sde/* /opt/sde && sudo ln -s /opt/sde/sde64 /usr/bin/sde
 
+    - name: Install dependencies
+      run: |
+        sudo apt update
+        sudo apt install -y g++-13
+        sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 1
+        sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 1
+        python -m pip install -r build_requirements.txt
+        python -m pip install pytest pytest-xdist hypothesis typing_extensions
+
+    - name: Build
+      run: spin build -- -Dallow-noblas=true -Dcpu-baseline=avx512_spr
+
+    - name: Meson Log
+      if: always()
+      run: cat build/meson-logs/meson-log.txt
+
+    - name: linalg/ufunc/umath tests on Intel SPR
+      run: |
+        export NUMPY_SITE=$(realpath build-install/usr/lib/python*/site-packages/)
+        export PYTHONPATH="$PYTHONPATH:$NUMPY_SITE"
+        cd build-install &&
+        sde -spr -- python -c "import numpy; numpy.show_config()" &&
+        sde -spr -- python -m pytest $NUMPY_SITE/numpy/_core/tests/test_umath* \
+                                     $NUMPY_SITE/numpy/_core/tests/test_ufunc.py \
+                                     $NUMPY_SITE/numpy/_core/tests/test_multiarray.py \
+                                     $NUMPY_SITE/numpy/linalg/tests/test_*
diff --git a/numpy/_core/src/npysort/x86-simd-sort b/numpy/_core/src/npysort/x86-simd-sort
index 8187e9a6d322..7060e3c76899 160000
--- a/numpy/_core/src/npysort/x86-simd-sort
+++ b/numpy/_core/src/npysort/x86-simd-sort
@@ -1 +1 @@
-Subproject commit 8187e9a6d322b3d0f202c0c8bc0c0c76fc9a6ec4
+Subproject commit 7060e3c768992441aa6454a6f9320a9fe1f870da
diff --git a/numpy/_core/src/npysort/x86_simd_qsort_16bit.dispatch.cpp b/numpy/_core/src/npysort/x86_simd_qsort_16bit.dispatch.cpp
index c210a9135356..8222fc77cae3 100644
--- a/numpy/_core/src/npysort/x86_simd_qsort_16bit.dispatch.cpp
+++ b/numpy/_core/src/npysort/x86_simd_qsort_16bit.dispatch.cpp
@@ -3,34 +3,9 @@
 
 #if defined(NPY_HAVE_AVX512_SPR)
     #include "x86-simd-sort/src/avx512fp16-16bit-qsort.hpp"
-/*
- * Wrapper function declarations to avoid multiple definitions of
- * avx512_qsort<uint16_t> and avx512_qsort<int16_t>
- */
-void avx512_qsort_uint16(uint16_t*, npy_intp);
-void avx512_qsort_int16(int16_t*, npy_intp);
-void avx512_qselect_uint16(uint16_t*, npy_intp, npy_intp);
-void avx512_qselect_int16(int16_t*, npy_intp, npy_intp);
-
+    #include "x86-simd-sort/src/avx512-16bit-qsort.hpp"
 #elif defined(NPY_HAVE_AVX512_ICL)
     #include "x86-simd-sort/src/avx512-16bit-qsort.hpp"
-/* Wrapper function defintions here: */
-void avx512_qsort_uint16(uint16_t* arr, npy_intp size)
-{
-    avx512_qsort(arr, size);
-}
-void avx512_qsort_int16(int16_t* arr, npy_intp size)
-{
-    avx512_qsort(arr, size);
-}
-void avx512_qselect_uint16(uint16_t* arr, npy_intp kth, npy_intp size)
-{
-    avx512_qselect(arr, kth, size, true);
-}
-void avx512_qselect_int16(int16_t* arr, npy_intp kth, npy_intp size)
-{
-    avx512_qselect(arr, kth, size, true);
-}
 #endif
 
 namespace np { namespace qsort_simd {
@@ -50,20 +25,12 @@ template<> void NPY_CPU_DISPATCH_CURFX(QSelect)(Half *arr, npy_intp num, npy_int
 
 template<> void NPY_CPU_DISPATCH_CURFX(QSelect)(uint16_t *arr, npy_intp num, npy_intp kth)
 {
-#if defined(NPY_HAVE_AVX512_SPR)
-    avx512_qselect_uint16(arr, kth, num);
-#else
     avx512_qselect(arr, kth, num);
-#endif
 }
 
 template<> void NPY_CPU_DISPATCH_CURFX(QSelect)(int16_t *arr, npy_intp num, npy_intp kth)
 {
-#if defined(NPY_HAVE_AVX512_SPR)
-    avx512_qselect_int16(arr, kth, num);
-#else
     avx512_qselect(arr, kth, num);
-#endif
 }
 
 /*
@@ -79,19 +46,11 @@ template<> void NPY_CPU_DISPATCH_CURFX(QSort)(Half *arr, npy_intp size)
 }
 template<> void NPY_CPU_DISPATCH_CURFX(QSort)(uint16_t *arr, npy_intp size)
 {
-#if defined(NPY_HAVE_AVX512_SPR)
-    avx512_qsort_uint16(arr, size);
-#else
     avx512_qsort(arr, size);
-#endif
 }
 template<> void NPY_CPU_DISPATCH_CURFX(QSort)(int16_t *arr, npy_intp size)
 {
-#if defined(NPY_HAVE_AVX512_SPR)
-    avx512_qsort_int16(arr, size);
-#else
     avx512_qsort(arr, size);
-#endif
 }
 #endif // NPY_HAVE_AVX512_ICL || SPR
 


Code review comments:
diff_hunk: @@ -198,15 +198,59 @@ jobs:
         sde -spr -- python -c "import numpy; numpy.show_config()" &&
         sde -spr -- python -m pytest $NUMPY_SITE/numpy/_core/tests/test_simd*
path: .github/workflows/linux_simd.yml
text: @user1:
```suggestion
```
There is no longer a need for this test, it would be better to move to the SPR job.

@author:
sure. Moved it to `inte_sde_spr` job. 

@user1:
No, what I meant is to append `$NUMPY_SITE/numpy/_core/tests/test_simd*` to the action `- name: linalg/ufunc/umath tests on Intel SPR` to speed up the test.

@author:
oh ok. But this probably fine too, right? It's the same set of tests just running in a different job.

@author:
and the SIMD tests take only a min, when compared to the umath tests take like 12 min. 

@user1:
Ok, lets put it in and try to optimize it later, thank you.