【问题标题】:How to take the high part of __m256__m256的高位怎么取
【发布时间】:2020-07-04 01:45:25
【问题描述】:

我有 __m256 或 __m256i,我想参加更高的部分。

鉴于__m256 variable,我知道我可以使用_mm256_extractf128_ps(variable, 1) 做到这一点

但对于较低的部分:_mm256_extractf128_ps(tr3, 0) 最好这样做 *((__m128*)&variable)

我不知道如何使用一些指针来获取高部分,就像我之前使用的低部分一样?

我可以添加一个数字或增加指针吗? *((__m128*)&variable+128)

【问题讨论】:

  • *((__m128*)&variable + 1)。这是简单的 C 指针算法。
  • @Jester 技术上未定义的行为,不是吗?
  • @fuz:实际上没有; __m128 是一个 may_alias 类型,如 char。取消引用指向__m256 对象的__m128* 实际上是安全的。不过,我不会推荐它。

标签: c pointers assembly intrinsics avx


【解决方案1】:

_mm256_extractf128_ps(v, 1) 是最好的方法。如果您的编译器编译效率不高,请使用更好的编译器(例如 clang 有一个非常好的 shuffle 优化器)。

对于低半部分,所有编译器都优化 _mm256_extractf128_ps(v, 0) 以不实际使用 vextractf128 指令,但内在函数最明确的方式是说你只想低 128 是 _mm256_castps256_ps128__m256i 的类似转换(_mm256_castsi256_si128) 或__m256d

这些通常编译为仅使用编译器包含向量变量的任何 YMM 寄存器的 XMM 低半部分,尽管有些编译器错过了优化错误,有时会发出无用的 vmovaps xmm, xmm 指令,而不是让后面的指令读取低 xmm 或任何寄存器的完整 ymm。

使用指针数学会鼓励编译器存储和重新加载,这是您通常不想要的。但在实践中,大多数编译器大部分时间都会将其优化回 ALU shuffle,即使您试图避免 shuffle-port 瓶颈并实际执行存储/重新加载。


我不推荐指针转换。但是,*((__m128*)&variable)((__m128*)&variable)[1] 是合法的,因为诸如 __m128 之类的内部向量类型与 char 类似——它们可以为任何其他类型设置别名,而不会违反严格的别名并导致未定义的行为。

C 指针数学将指针移动指向类型的 1 个大小单位。例如+1__m128* 上移动 16 个字节,即一个 __m128。这就是++ 总是在数组上迭代指针的原因。 Pointer Arithmetic

由于您想要第二个__m128,您应该将1 添加到您的__m128*。例如*(1 + (__m128*)&variable)。 C [] 语法 is defined 就指针添加 + 取消引用而言,所以我们可以这样写,将 [] 应用于强制转换结果。这两种写法都清楚地表明+1 适用于演员表之后的__m128*,而不是演员表之前&var__m256。尽管 IIRC,强制转换的优先级高于 +1*((__m128)&var + 1) 也是安全的。但反过来写意味着你以后阅读代码时不必记住这一点。


在 GNU C 中,内部类型使用 __attribute__((may_alias)) 定义。在 MSVC 中,始终允许使用别名。 Is `reinterpret_cast`ing between hardware SIMD vector pointer and the corresponding type an undefined behavior? 这使得指针转换对于这种类型的双关语来说是安全的。

任何其他类型,例如((float*)&vec)[0],都会违反严格的别名并成为UB。

正如我所说,由于您通常希望编译器使用 shuffle 指令,因此处理指针需要编译器优化所有指针。使用内在函数。

【讨论】:

    猜你喜欢
    • 2014-02-18
    • 2016-09-01
    • 1970-01-01
    • 2014-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-31
    • 1970-01-01
    相关资源
    最近更新 更多