Lokathor / safe_arch

Exposes arch-specific intrinsics as safe function (via cfg).
https://docs.rs/safe_arch
Apache License 2.0
47 stars 8 forks source link

_mm256_insertf128_si256(avx) vs _mm256_inserti128_si256 (avx2) #67

Closed Lokathor closed 4 years ago

Lokathor commented 4 years ago

It seems like the docs and even signature for _mm256_insertf128_si256 and _mm256_inserti128_si256 are essentially the same, however based on the names and the Felix Cloutier Notes it seems like _mm256_insertf128_si256 is mis-typed and should be operating on floating data, not integer data.

This would be a fairly simple fix, we can just throw in an extra cast or two if needed. The question is if this conclusion is correct and if we should make this adjustment for the user. Normally I'd be against safe_arch doing a "fix" like this but in this case it's the intel intrinsics who are wrapping the assembly wrong, so it feels fair to give proper direct access to the assembly.

Pings to:

Evrey commented 4 years ago

Intrinsics Guide is down, but here's stuff right out of Intel's manual:

VINSERTF128 __m256 _mm256_insertf128_ps (__m256 a, __m128 b, int offset); VINSERTF128 __m256d _mm256_insertf128_pd (__m256d a, __m128d b, int offset); VINSERTF128 __m256i _mm256_insertf128_si256 (__m256i a, __m128i b, int offset);

5-286 Vol. 2C (p. 2178 of the combined manual)

Aaand from that same manual…

VINSERTI128 __m256i _mm256_insertf128_si256 (__m256i a, __m128i b, int offset);

5-290 Vol. 2C (p. 2182 of the combined manual)

Lookin' like a typo, especially given that the manual has no mention of the _mm256_inserti128_si256 version. AMD manuals don't mention the intrinsics.

Anyways, as you can see for the vinsertf128 version, there are three intrinsics of different types that generate the exact same instruction. So you can just keep the types or drop that intrinsic or whatever else. The important ones are _ps and _pd.

The vinserti128 version is important to have and keep as is, though. x86 SIMD has two separate data paths for integer and float vectors. Crossing paths adds extra latency, thus slowing down the code. Whatever namings and types you pick, make sure to make this property transparent to users.

Lokathor commented 4 years ago

Oh, great, now we get to convince T-libs that there's a bug in core which needs a breaking change to properly fix.

Just great.

joshtriplett commented 4 years ago

I don't know the policies of the libs team here, but I think it's reasonable to make such a change, given a crater run. Thanks for doing the detailed research to back it up.

joshtriplett commented 4 years ago

Can you write a PR for the change you would propose, so we can put it through a crater run?

Lokathor commented 4 years ago

Yeah, I'll probably have time to do that tomorrow after the T-lang meeting

Evrey commented 4 years ago

To clarify, I meant that Intel's VINSERTI128 __m256i _mm256_insertf128_si256 (__m256i a, __m128i b, int offset); is a typo and should've been _mm256_inserti128_si256. The signatures may be intended. At least all C headers I know and all the articles out there and all the manuals agree on that, though nonsensical, typing of VINSERTF128 __m256i _mm256_insertf128_si256 (__m256i a, __m128i b, int offset);.

E: To clarify the clarification, _mm256_insertf128_si256 looks correct, but nonsensical because Intel. _mm256_inserti128_si256 makes sense. My guess is that the signature of the former is old convenience stuff, which when truly used on integer vectors will trigger costly domain transfers. And the latter is there to replace the former with a real cheap integer-domain version of that operation. As such, the docs should state to prefer ignoring the former and only use the latter.

Lokathor commented 4 years ago

Alright, I spoke with Evrey some more on Discord and we came to the agreement that:

Evrey commented 4 years ago

I love the typos in your summary.