_builtin_prefetch()中第二个参数的影响是什么?
这里的GCC doc指定了_buitin_prefetch的用法。
第三个论点是完美的。 如果为0,则编译器生成prefetchtnta(%rax)指令如果为1,编译器生成prefetcht2(%rax)指令如果为2,则编译器生成prefetcht1(%rax)指令如果为3(默认值),则编译器生成prefetcht0 (%rax)指令。
如果我们改变第三个参数,操作码已经相应地改变了。
但第二个论点似乎没有任何影响。
__builtin_prefetch(&x,1,2); __builtin_prefetch(&x,0,2); __builtin_prefetch(&x,0,1); __builtin_prefetch(&x,0,0);
以上是生成的示例代码:
以下是assembly:
27: 0f 18 10 prefetcht1 (%rax) 2a: 48 8d 45 fc lea -0x4(%rbp),%rax 2e: 0f 18 10 prefetcht1 (%rax) 31: 48 8d 45 fc lea -0x4(%rbp),%rax 35: 0f 18 18 prefetcht2 (%rax) 38: 48 8d 45 fc lea -0x4(%rbp),%rax 3c: 0f 18 00 prefetchnta (%rax)
人们可以通过第三个参数来观察操作码的变化。 但即使我更改了第二个参数(指定读或写),汇编代码仍然相同。 和。 所以它没有向机器提供任何信息。 那么第二个论点的目的是什么?
从你发布的同一个链接:
有两个可选参数, rw和locality 。 rw的值是编译时常量1或0; 一个意味着预取正在准备写入存储器地址,零,默认值意味着预取正准备读取。
x86架构在读取和写入预取之间没有区别。
这并不意味着您应该忽略第二个参数,因为在C中编写代码是为了提高可移植性。 即使在您的机器中没有使用第二个参数,也可以在编译到不同的体系结构时使用它。
编辑正如@PeterCordes在他的评论中指出的那样,x86实际上有一个预取指令,可以预期写入。
它与其他预取指令不同,因为它使获取的行的其他缓存实例无效(并将其设置为独占状态)。
正如玛格丽特所指出的那样,其中一个武器是rw 。 基线x86-64(SSE2)不包括写预取指令,但它们作为ISA扩展存在。 像往常一样,编译器不会使用它们,除非你告诉他们你正在编译支持它的目标。
这两条指令是: PREFETCHW和PREFETCHWT1 。
PREFETCHW最初出现在AMD的3DNow!中,但它有自己的特性位,因此CPU可以表示支持它,但不支持其他3dNOW(MMX regs中的打包float
)指令。
我不确定是否有任何CPU支持PREFETCHWT1。 基于这个邮件列表post ,我认为它最初可能在Xeon PHI中,和/或与AVX512相关联。
__builtin_prefetch(p,1,2);
编译如下:
- 没有
-m
选项的PREFETCHT1,或-march=haswell
或更旧的Intel。 - 具有AMD目标的PREFETCHW,如
-march=k8
或-march=bdver2
(Piledriver)。 - 使用
-march=broadwell
或更新的Intel SnB系列进行PREFETCHW。 - PREFETCHWT1和
-mprefetchwt1
。 (如果PREFETCHW也可用,gcc将其用于locality = 3,但PREFETCHWT1用于locality <= 2。)
在Godbolt编译器资源管理器上查看它,对于-march=haswell
vs. -march=broadwell -mprefetchwt1
。 或者自己修改编译器args。
奇怪的是,gcc的x86目标选项似乎没有提到单独的开关来启用PREFETCHW; 它仅作为-march=whatever
一部分启用。 不过,这个SO答案使用-mprfchw
来启用它。
另请注意,其0F 0D r/m8
机器码编码在没有PREFETCHW或3DNow的CPU上解码为多字节NOP ! function位。 在早期的64位Intel CPU上,这是一个非法指令。 (较新版本的Windows要求PREFETCHW在没有故障的情况下执行,并且在该上下文中,人们谈论CPU“支持PREFETCHW”,即使它作为NOP运行)。
但是,最好使用读取意图预取而不是NOP。 但是你可能不想做PREFETCHW和PREFETCHT0,因为太多的预取指令并不是一件好事。 (特别是英特尔IvyBridge,它具有预取指令吞吐量的某种性能缺陷。但是OTOH,它将作为NOP运行PREFETCHW,因此在这种情况下你只能得到一个预取。)