8 ms·
> _mm256_blend_pd is very fast instruction, a single cycle of latency. The highway’s emulation is going to be way more expensive. Actually it uses exactly the
by janwas 5y ago
> _mm256_blend_pd is very fast instruction, a single cycle of latency. The highway’s emulation is going to be way more expensive.
Actually it uses exactly the same instruction :) https://github.com/google/highway/blob/master/hwy/ops/x86_256-inl.h#L2704 https://github.com/google/highway/blob/master/hwy/ops/x86_25...
Thanks for sharing the list! Out of curiosity, can you expand on what _mm256_permute4x64_pd is used for?
> _mm_addsub_ps (that one is vertical but still missing from highway)
Indeed, we have not needed complex-valued functions yet. AFAIK NEON does not have such an instruction but it could be emulated with an extra XOR+constant. Will add to wishlist, we implement them whenever there's a use case.
> I have tons of #ifdef there
Seems reasonable if you only target v7 and ASIMD; but #ifdef is increasingly infeasible now that SVE and Risc-V V are coming, no?
> to support NEON which differs substantially, there’s stuff like vrev64q_f32 and vextq_f32
Those can actually be bridged just fine, they correspond to Shuffle2301 and CombineShiftRightLanes.
> Even if you expose all the missing horizontal stuff in highway — won’t be much better than intrinsics. Such code ain’t gonna use AVX512 when available.
Because of the hardcoded vector size? I agree that's best avoided, in your case perhaps by batching the matrix mul and applying SIMD over that dimension instead?
Even if not, I'd rather have type-safety, friendlier function names and gaps in the ISA filled, but tastes differ.
- Const-me 5y ago> can you expand on what _mm256_permute4x64_pd is used for? In one place I was doing single-pass marching cubes on multiple FP32 scalar fields. A source data for every cube is 8 FP32 number in 1 AVX register. Sometimes I need to broadcast FP32 lanes from the vector, where the source index is known at compile time. For most of these indices, a combo of _mm256_movehdup_ps/_mm256_moveldup_ps + _mm256_permute4x64_pd is the fastest way to do so. In another place I needed to broadcast FP64 values from non-zero lane. In another place I wanted to avoid MXCSR error flag for 3D FP64 vectors: // Duplicate Z into W to avoid division by zero size = _mm256_permute4x64_pd( size, _MM_SHUFFLE( 2, 2, 1, 0 ) ); In a few other places it’s just math e.g. const __m256d b_xxy = _mm256_permute4x64_pd( b, _MM_SHUFFLE( 3, 1, 0, 0 ) ); const __m256d bw_yzz = _mm256_permute4x64_pd( bWeight, _MM_SHUFFLE( 3, 2, 2, 1 ) ); __m256d tmp = _mm256_mul_pd( b_xxy, bw_yzz ); > we have not needed complex-valued functions yet Wasn’t related to complex numbers, I was doing something like that, saving a few instructions: https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_two_points https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_lin... > but #ifdef is increasingly infeasible now that SVE and Risc-V V are coming, no? I think that’s wishful thinking like all these years of Linux on desktop, or rewriting everything in Rust. I think ARM is good enough for most applications, except very small niches (very low power, very price-sensitive, mostly embedded). > Those can actually be bridged just fine Yeah, but other things can’t. For one, ARM has 8-byte SIMD vectors. Quite useful for a library which implements non-trivial algorithms processing 2D vector data with tons of FP32 2D vectors. Another thing, this whole source file https://github.com/Const-me/DtsDecoder/blob/master/Utils/store3-sse.hpp https://github.com/Const-me/DtsDecoder/blob/master/Utils/sto... implementing an equivalent of a single vst3q_s16 NEON instruction. That code is called in a loop which does not do much else and is inlined, i.e. these 9 shuffle constants stay in vector registers.
- janwas 5y agoThanks for sharing the examples! Looks like broadcast and replicating one element, which works if we know there are only 4 elements. > I was doing something like that, saving a few instructions Oh, nice one. > I think ARM is good enough for most applications, except very small niches (very low power, very price-sensitive, mostly embedded). Are you talking about the ARM arch vs Risc-V? That may be, but ARM is also getting SVE, and adding yet another #if for that is going to be expensive. > Yeah, but other things can’t. For one, ARM has 8-byte SIMD vectors. hm, Highway does support half vectors which map nicely to the non-q instructions. We also support 8-bit StoreInterleaved3 which is implemented similar to yours (more instructions but fewer constants): https://github.com/google/highway/blob/master/hwy/ops/x86_128-inl.h#L4971 https://github.com/google/highway/blob/master/hwy/ops/x86_12... In my experience, integer mul are the hardest to bridge, but at least for dot products even that is feasible.