gpt4 book ai didi

c - 强制编译器使用 Intrinsics 中的内存操作数

转载 作者:行者123 更新时间:2023-12-05 01:55:21 26 4
gpt4 key购买 nike

是否存在强制 C 编译器直接使用内存操作数的语法?

在过去美好的 asm 时代,我们只需在指令中写入操作数的位置 - “真实”寄存器或内存指针(由地址指向的位置)。

但在 C 的内在函数伪汇编中,我看不到强制编译器在指令中使用内存指针的方法(拒绝从内存(缓存)加载数据到“寄存器”,即垃圾寄存器文件加载内容到缓存和导致重新加载并受到惩罚)。

我知道程序员很容易简单地将“可变”操作数写入 instinsic 并让编译器决定是先从内存加载还是直接使用它(如果可能)。

当前任务:我想计算 AVX2 CPU 上一系列 8x8 8 位 block 的 SAD,其中包含 512 字节的寄存器文件(16 个 ymm“寄存器”,每个 32 字节)。因此它可以加载 8 个 8x8 8 位源 block 以完全填充可用的 AVX2 寄存器文件。

我想在所有 寄存器文件中加载源 block ,并针对这些源 block 和每个引用位置仅测试内存中的不同“引用”位置一次。所以我想阻止 CPU 从缓存中加载 ref block 到寄存器文件,并在 sad 指令中使用“内存操作数”。

使用 asm 我们可以简单地写一些类似的东西

(load all 16 ymm registers with src)
vpsadbw ymm0, ymm0, [ref_base_address_register + some_offset...]

但是在 C 文本中它是内在的

__m256i src = load_src(src_pointer);
__m256i ref = load_ref(ref_pointer);
__m256i sad_result= _mm256_sad_epu8(src, ref)

它没有办法让编译器使用有效的内存操作数

__m256i src = load_src(src_pointer);
__m256i sad_result= _mm256_sad_epu8(src, *ref_pointer)

或者取决于“任务大小”,如果编译器用完可用寄存器,它将自动切换到内存操作数版本,程序员可以编写

__m256i sad_result=_mm256_sad_epu8(*(__m256i*)src_pointer, *(__m256i*)ref_pointer)

并期望编译器将加载 2 个操作数之一到寄存器文件并使用内存中的下一个?

最佳答案

不,没有,除了一些具有指针操作数的特定内在函数,即使它们不是纯加载或纯存储1

内在函数的部分目的是抽象出寄存器分配细节,就像它对 intdouble 所做的那样,因此由编译器将内容保留在当这是一件好事时注册。这通常会发生,因此,如果您担心优化器未能将负载内在函数折叠到内存源操作数(例如在 https://godbolt.org/ 上或本地),请检查 asm 输出。 AVX(VEX 编码)甚至允许折叠未对齐的负载,因为与传统 SSE 不同,默认情况下不需要对齐。

当编译器失败时,这可能会很糟糕,就像许多用于 _mm256_cvtepu8_epi32( _mm_loadl_epi64(p) ) 的编译器一样 - GCC 用于发出实际的 movq 加载和 reg -reg vpmovzxbd。只有在 GCC9 及更高版本中,我们才能获得内存源 vpmovzxbd。 ( Loading 8 chars from memory into an __m256 variable as packed single precision floats )

或者对于您的情况,如果编译器溢出了错误的东西,唯一的解决方法是提交优化错误报告并等待新的编译器版本。或者用 asm 编写一个版本(内联或独立)。


内在模型的设计者还想提供 load/loadustore/storeu 内在函数将对齐信息传达给编译器。 (对于 float/double,在 float*__m128* 或其他任何东西之间进行转换。)_mm_load_si128((__m128i*)foo) 是 < em>完全与 *(__m128i*)foo 完全相同并且与访问 __m128i 数组的元素几乎相同,如果编译器不能查看数组并将其保存在寄存器中。参见 Is `reinterpret_cast`ing between hardware SIMD vector pointer and the corresponding type an undefined behavior?

令人困惑的是,加载内在函数看起来像 asm 加载/存储,但在启用优化时它们实际上根本不同。


脚注 1:AVX-512 有一些特殊指令,这些指令具有相应有趣的内在函数,如 VPMOVDB mem128 {k}, zmm2 - void _mm512_mask_cvtepi32_storeu_epi8(void * d, __mmask16 k, __m512i a);。能够存储到内存为 Xeon Phi(骑士登陆)提供了一种在没有 AVX-512BW 的情况下为 vmovdqu8 进行字节屏蔽存储的方法。

关于c - 强制编译器使用 Intrinsics 中的内存操作数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70261138/

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