gpt4 book ai didi

c++ - 声明 "intrinsics"只是对编译器的建议是否正确?

转载 作者:行者123 更新时间:2023-11-27 23:42:13 26 4
gpt4 key购买 nike

我对内在函数、simd 和一般的低级编程真的一窍不通。我正在迈出第一步,但就我所见,我正在使用的所有内部函数(Intel ones 现在)只是 C++ 通用代码,没有任何“特殊”或专用关键字。

这似乎是那些“函数列表”和编译器之间的一种协议(protocol),例如告诉编译器如果我使用这样的东西:

__m128d vA = _mm_load_pd(a);

应该vA 变量视为XMM 寄存器,而不是将其分配到内存中。但它不能保证(因为 __m128d,最后,它是一个 C++ union/结构对象,可以驻留在内存中)。

我说的对吗?或者引擎盖下还有更多的黑魔法?

Compiler 如何“以某种方式”处理这些函数而不是通用函数?通过解析代码匹配的规则?像这样的东西?

它对 Web 开发人员来说非常有吸引力 :)

最佳答案

您实际上是在问两个不同的问题:

(1) 编译器如何决定将我的 SIMD 变量放在哪里?在内存中还是在寄存器中?

(2) 内在的“契约”有多具体?它是否总是发出特定指令?

第一个问题的答案对于 SIMD 与任何其他类型的变量并没有什么不同。在 C/C++ 中,通常使用 automatic variables因为这些最有可能最终出现在寄存器中。编译器可以根据上下文自由安排实际指令和寄存器使用,并且通常会根据代码中的“寄存器压力”大小将数据移入和移出寄存器以“堆栈内存”。

与在汇编中编写它相比,这种灵 active 是一件“好事”,在汇编中,程序员可以确切地决定在何时使用哪些寄存器以及以什么顺序执行指令。编译器通常可以混合其他附近的代码或做其他难以保持直线的优化,它可以利用架构差异。例如,在 DirectXMath 中我为 x86(32 位)和 x64(64 位)编写了相同的内部代码,编译器可以使用 x64 中可用的 8 个额外寄存器。如果我使用内联汇编,我将不得不以两种不同的方式编写它,并且可能不止于此,我很快就会谈到一些额外的差异。

When writing SIMD code, you really want to maximize the work with data already in a register because the load/store overhead to memory often costs as much performance as you get from doing a few SIMD instructions vs. scalar. As such, you will usually write SIMD intrinsics to do an explicit load into a bunch of 'automatic variables' but keep in mind that likely only 8 or so of them are going to really be in a register at a time. You do want to do enough work that the compiler can fill in the gaps. You then store the result to memory. As such, you really don't do stuff like auto a = new __m128d;. There's also the additional complexity of the implied aligment (__m128d must be 16-byte aligned, and while x64 new does that x86 new does not).

第二个答案有点复杂。一个给定的内在函数通常被定义为一个给定的指令,一些内在函数实际上是指令的组合,但是编译器在选择确切的指令时可能会选择使用目标平台的一些知识。下面是几个例子:

  • __m128 _mm_add_ps (__m128 a, __m128 b) 被定义为 SSE 指令 addps 并且通常如此发出。但是,如果您使用 /arch:AVX/arch:AVX2 构建,编译器将使用 VEX prefix和指令 vaddps

  • __m128d _mm_fmadd_pd (__m128d a, __m128d b, __m128d c) 被定义为 FMA3 指令,但编译器实际上可以发出 vfmadd132pd, vfmadd213pd vfmadd231pd 取决于确切的寄存器使用。事实上,编译器甚至可以决定使用 vmulpd 后跟 vaddpd 更快,这取决于硬件指令成本函数的确切指令时间它正在使用。

Note that while it is certainly possible for the compiler implementer to decide say that they could optimize __m128 _mm_shuffle_ps (__m128 a, __m128 b, unsigned int imm8) where the registers a and b are the same and choose emit a vpermilps instead of a shufps if you are building with /arch:AVX. That would be 'in contract' with the intrinsic. In practice, however, intrinsics tend to be treated a bit special and strongly prefer the instruction they are defined as because you often use them in particular contexts based on hardware feature detection. So you normally can count on a particular instrinic to end up being the instruction you expect or a very close variant of it.

简而言之,所有 C/C++ 都是对编译器的“提示”,因为源代码描述了您想要的确切计算,但编译器可以自由地实际发出代码实现相同的结果,但顺序可能不同或使用与您可能假设的指令不同的指令。

The Intel Intrinsics Guide is a good resource for exploring intrinsics.

You might also find some of my blog posts related to intrinsics useful.

The DirectXMath Programmer's Guide also has some useful tricks & tips for intrinsics usage sprinkled throughout so it's worth a read and it's only 6 pages so it won't take that long. See Microsoft Docs

关于c++ - 声明 "intrinsics"只是对编译器的建议是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53762534/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com