_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) 

人们可以通过第三个参数来观察操作码的变化。 但即使我更改了第二个参数(指定读或写),汇编代码仍然相同。 和。 所以它没有向机器提供任何信息。 那么第二个论点的目的是什么?

从你发布的同一个链接:

有两个可选参数, rwlocalityrw的值是编译时常量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,因此在这种情况下你只能得到一个预取。)