1

what is difference between *(B*)(&A) and (B)A I'm using simd codes. but I confront problem.
I couldn't cast my own vector4 type to __m128

So I did like this
this works well

#define XMM128Float(VECTOR4FLOAT) *(__m128*)(&VECTOR4FLOAT)

Vector4<float> vec4{};
XMM128Float(&vec4) = _mm_mul_ps(XMM128Float(*this), XMM128Float(*this));

I wanna know why (__m128)vec4 doesn't works....
What is difference between them.

#define XMM128Float(VECTOR4FLOAT) *(__m128*)(&VECTOR4FLOAT)

template <>
[[nodiscard]] inline SIMD_CONSTEXPR auto Vector<4, float>::sqrMagnitude() const noexcept
{
    Vector<4, float> Result;
        
    XMM128Float(Result) = _mm_mul_ps(XMM128Float(*this), XMM128Float(*this));
    return Result.x + Result.y + Result.z + Result.w;
}

I wrote my SIMD function like this.

i'm using MS BUILD 16 Compiler

SungJinKang
  • 409
  • 3
  • 9
  • One of them is well-defined :D – M.M Mar 22 '21 at 10:26
  • @M.M: And unlike what one might guess (from the normal C++ strict-aliasing rules), the one's that's well-defined is the pointer-cast: [Is \`reinterpret\_cast\`ing between hardware SIMD vector pointer and the corresponding type an undefined behavior?](https://stackoverflow.com/q/52112605). Although in MSVC, pointer-cast type punning is always well-defined (as long as you don't read outside of an array or struct): MSVC is like `gcc -fno-strict-aliasing`. – Peter Cordes Mar 22 '21 at 10:58
  • @PeterCordes Re "in MSVC pointer-cast type punning is always well-defined": Is that officially documented? Is it also true when compiling with `-Ox` (maximum optimization)? – njuffa Mar 22 '21 at 19:41
  • @njuffa: Yes, but I can't find it at the moment. I'm pretty sure I've seen MSDN docs with a recommendation to do stuff like `reinterpret_cast(my_unsigned)` or equivalent `*(float*)&my_unsigned`. It's also widely accepted by developers that MSVC doesn't break strict aliasing, and they wouldn't be able to introduce type-based aliasing optimizations without breaking existing code, but as I said I think MS does actually embrace those idioms. (Perhaps to lock people in to their compiler, with code that's not portable, or to make GCC/clang look bad when it "breaks their code"?) – Peter Cordes Mar 22 '21 at 20:46
  • @PeterCordes My $0.02 as a retired SW engineer whose entire career was in industry: By and large (with exceptions) businesses try not to invalidate existing customers' code base. Beyond that, at times they go to great length to keep broken customer code working. In Microsoft's case, some of those customers may be *internal* customers. Open-source projects are rarely restricted in similar fashion and bluntly direct users to fix their non-standard compliant code (I found myself at the receiving end of that once, with gcc: signed integer overflow in code that had been in use for almost 20 years). – njuffa Mar 22 '21 at 21:49
  • @njuffa: yeah, definitely. x86 CPU vendors give similar treatment to backwards compat for existing important binaries (like TLB handling for the Win95 kernel, as discussed [in comments](//stackoverflow.com/a/18388700/224132)). The only question is how officially MSVC documents / encourages this. It's well known that it works in practice and is widely used. But like I said, I *think* I've seen the `(float&)some_int` idiom on MSDN in some official MSVC docs at some point, not just a forum discussion. That stuck in my mind exactly because of being official endorsement, not de-facto acceptance. – Peter Cordes Mar 22 '21 at 21:59

1 Answers1

2

what is difference between *(B*)(&A) and (B)A

*(B*)(&A) uses addressof operator to get the address of the object named by A, then explicitly converts1 that pointer to another pointer type B*, then it indirects through2 that converted pointer.

(B)A explicitly converts the object named by A into a new object of type B.

I wanna know why (__m128)vec4 doesn't works....

You cannot convert an value of a class type A into another type B unless you have defined a conversion operator for A that can convert to the type B or another type that is convertible to B (or unless B is also a class and has a converting constructor accepting A parameter or another type convertible to A) - note that only one such user defined conversion can be used in one conversion sequence; other conversions must be standard conversions.


1 Don't use explicit conversions aka C-style casts in C++. Use the specific static_cast, reinterpret_cast and const_cast instead.

2 Note that accessing the object through the reinterpreted pointer may generally result in undefined behaviour depending on the involved types. It is allowed only in specific cases. Consult the manual of your compiler to find if __m128 is such case.

P.S. Avoid unnecessary macros. What you've written could be defined as an inline function instead.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Some compilers have special semantics for SIMD types... – Marc Glisse Mar 22 '21 at 10:00
  • @MarcGlisse what specifically did you have in mind? – Sneftel Mar 22 '21 at 10:04
  • 1
    Gcc allows some casts between vector types (more with `-flax-vector-conversions`) with the same semantics as a pointer cast, not a conversion. – Marc Glisse Mar 22 '21 at 10:09
  • Can i shorten this code ```#define XMM128Float(VECTOR4FLOAT) *(__m128*)(&VECTOR4FLOAT)``` – SungJinKang Mar 22 '21 at 10:13
  • @MarcGlisse Seems to not work with classes: https://godbolt.org/z/T76jnc884 (sidenote to anyone reading, please note that the documentation says *"This option should not be used for new code. "*) – eerorika Mar 22 '21 at 10:19
  • Note that for Intel intrinsics at least, `__m128*` is allowed to alias anything, just like `char*`. So it's safe to point it at things other than `float`s. [Is \`reinterpret\_cast\`ing between hardware SIMD vector pointer and the corresponding type an undefined behavior?](https://stackoverflow.com/q/52112605) – Peter Cordes Mar 22 '21 at 10:53