_mm256_shuffle_epi8/vpshufb in Odin

Hello all,

I would like to execute the instruction ‘_mm256_shuffle_epi8’ (intel intrinsics) aka ‘VPSHUFB’ (x64 simd instruction).

I’vs seen the 128 bits equivalent (‘_mm_shuffle_epi8’/‘PSHUFB’ in ‘ssse3.odin’) but not the 256 bits version. ‘simd.swizzle’ seemed to do the job, but apparently the second argument is a compile-time constant.

Thanks in advance !

(context, as usual: porting ‘simdjson’ to Odin, used in multiple places, e.g. : simdjson/src/haswell.cpp at master · simdjson/simdjson · GitHub )

For info: I suppose it’s a work in progress (some simd stuff was added very recently in Odin), so I just wrote a less-efficient stub:

@(enable_target_feature=“ssse3”)
_mm256_shuffle_epi8_stub :: proc (a, b: simd.u8x32) → simd.u8x32 {
u := transmute([2]simd_x86.__m128i)a
v := transmute([2]simd_x86.__m128i)b
result : [2]simd_x86.__m128i
result[0] = simd_x86._mm_shuffle_epi8(u[0], v[0])
result[1] = simd_x86._mm_shuffle_epi8(u[1], v[1])
return transmute(simd.u8x32)result
}

It does the job in the meantime

If you need it, you should be able to foreign import the AVX intrinsics in much the same manner as core:simd/x86 imports all of the ones it currently defines.
https://github.com/odin-lang/Odin/blob/d3b1aaad18e7a1445992aea76dfb6fa00e5a9d80/core/simd/x86/ssse3.odin#L109

That being said, I’m not sure if there’s a complete list of their names somewhere to use.

1 Like

Thanks again for your help Barinzaya.

Yes, I tried to do that (although I don’t really know what I’m doing here):

package lalala

import “core:fmt”
import simd_x86 “core:simd/x86”
import “core:simd”

@(require_results, enable_target_feature=“avx2”)
_mm256_shuffle_epi8_test :: #force_inline proc “c” (a, b: simd_x86.__m256i) → simd_x86.__m256i {
return transmute(simd_x86.__m256i)pshufb256(transmute(simd.u8x32)a, transmute(simd.u8x32)b)
}

@(private, default_calling_convention=“none”)
foreign _ {
@(link_name = “llvm.x86.avx2.pshuf.b.256”)
pshufb256 :: proc(a, b: simd.u8x32) → simd.u8x32 —
}

@(enable_target_feature=“avx2”)
main :: proc() {
fmt.printfln(“simd test: %v”, _mm256_shuffle_epi8_test((10), (5)))
}

It fails:

undefined reference to `llvm.x86.avx2.pshuf.b.256’

But I don’t know how it all works, it could be for many different reasons, the actual ‘link_name’ being one of them …

Yes, I couldn’t find the appropriate “link_name” and guessed based on old llvm code…

Apparently it’s just llvm.x86.avx2.pshuf.b. No 256 for some reason.
https://github.com/llvm/llvm-project/blob/b003face11fadc526a6f816243441f486ffc958d/llvm/test/CodeGen/X86/avx2-intrinsics-x86.ll#L693
I’m still not sure where the best source to find these names is, though (if there’s even a single list). I guess that source file is the closest there is to a “list”.

2 Likes

YES it works !!!
Thanks a million !

@(require_results, enable_target_feature=“avx2”)
_mm256_shuffle_epi8_test :: #force_inline proc “c” (a, b: simd_x86.__m256i) → simd_x86.__m256i {
return transmute(simd_x86.__m256i)pshufb256(transmute(simd.u8x32)a, transmute(simd.u8x32)b)
}

@(private, default_calling_convention=“none”)
foreign _ {
@(link_name = “llvm.x86.avx2.pshuf.b”)
pshufb256 :: proc(a, b: simd.u8x32) → simd.u8x32 —
}

1 Like