*(__m128*)(&A) 和 (__m128)A 有啥区别

Posted

技术标签:

【中文标题】*(__m128*)(&A) 和 (__m128)A 有啥区别【英文标题】:what is difference between *(__m128*)(&A) and (__m128)A*(__m128*)(&A) 和 (__m128)A 有什么区别 【发布时间】:2021-03-22 09:46:07 【问题描述】:

*(B*)(&A)(B)A 有什么区别 我正在使用 simd 代码。但我遇到了问题。 我无法将自己的 vector4 类型转换为 __m128

所以我确实喜欢这个 这很好用

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

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

我想知道为什么(__m128)vec4 不起作用.... 它们之间有什么区别。

#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;

我这样写了我的 SIMD 函数。

我正在使用 MS BUILD 16 编译器

【问题讨论】:

其中一个是明确定义的:D @M.M:与人们可能猜到的不同(根据正常的 C++ 严格别名规则),定义明确的是指针转换:Is `reinterpret_cast`ing between hardware SIMD vector pointer and the corresponding type an undefined behavior?。尽管在 MSVC 中,指针转换类型的双关语总是定义明确的(只要您不读取数组或结构之外的内容):MSVC 就像 gcc -fno-strict-aliasing @PeterCordes Re“在 MSVC 指针转换类型中,双关语总是明确定义的”:这是官方记录的吗?用-Ox(最大优化)编译时也是这样吗? @njuffa:是的,但我现在找不到。我很确定我已经看过 MSDN 文档,其中建议执行reinterpret_cast&lt;float&amp;&gt;(my_unsigned) 或等效*(float*)&amp;my_unsigned 之类的操作。开发人员也广泛接受 MSVC 不会破坏严格的别名,并且他们无法在不破坏现有代码的情况下引入基于类型的别名优化,但正如我所说,我认为 MS 确实接受了这些习惯用法。 (也许是用不可移植的代码将人们锁定在他们的编译器中,或者让 GCC/clang 在“破坏他们的代码”时看起来很糟糕?) @PeterCordes 作为一名退休的软件工程师,我的 0.02 美元,他的整个职业生涯都在行业中:总的来说(除了例外)企业尽量不使现有客户的代码库失效。除此之外,有时他们会竭尽全力保持损坏的客户代码正常工作。在 Microsoft 的案例中,其中一些客户可能是内部客户。开源项目很少以类似的方式受到限制,并且直截了当地指导用户修复他们的非标准兼容代码(我发现自己曾经处于接收端,使用 gcc:已使用近 20 年的代码中的有符号整数溢出年)。 【参考方案1】:

*(B*)(&amp;A)(B)A 有什么区别

*(B*)(&amp;A) 使用addressof 操作符得到A 命名的对象的地址,然后将该指针显式转换1 到另一个指针类型B*,然后通过 2 转换后的指针。

(B)AA 命名的对象显式转换为B 类型的新对象。

我想知道为什么 (__m128)vec4 不起作用....

您不能将类类型A 的值转换为另一种类型B,除非您为A 定义了一个可以转换为B 类型或其他可转换为@987654334 的类型的转换运算符@(或者除非B 也是一个类并且具有接受A 参数或可转换为A 的另一种类型的转换构造函数) - 请注意,在一个转换序列中只能使用一个这样的用户定义转换;其他转换必须是标准转换。


1 不要在 C++ 中使用显式转换,即 C 样式转换。请改用特定的static_castreinterpret_castconst_cast

2 请注意,通过重新解释的指针访问对象通常可能会导致未定义的行为,具体取决于所涉及的类型。仅在特定情况下才允许。请查阅您的编译器手册,了解__m128 是否属于这种情况。

附:避免不必要的宏。你写的东西可以定义为内联函数。

【讨论】:

一些编译器对 SIMD 类型有特殊的语义... @MarcGlisse 你具体有什么想法? Gcc 允许在向量类型之间进行一些转换(更多 -flax-vector-conversions),其语义与指针转换相同,而不是转换。 我可以缩短这个代码#define XMM128Float(VECTOR4FLOAT) *(__m128*)(&amp;VECTOR4FLOAT) @MarcGlisse 似乎不适用于类:godbolt.org/z/T76jnc884(任何阅读者的旁注,请注意文档中说“此选项不应用于新代码。”)

以上是关于*(__m128*)(&A) 和 (__m128)A 有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

两个 __m128i 的两个位到一个 __m128i 的四个位 -SSE

将 __m128i 值转换为 std::tuple

__m128, SSE4 中最大绝对值的符号

如何将 __m128 反转为整数

使用_mm_load_pd时函数崩溃

如何使用 SSE 将 _m128i 转换为无符号整数?