【问题标题】:Why does SSE/AVX lack loading an immediate value?为什么 SSE/AVX 缺少加载即时值?
【发布时间】:2022-12-05 04:48:01
【问题描述】:

据我所知,SSE/AVX 中没有加载立即数的指令。一种解决方法是将值加载到普通寄存器和 movd,但编译器似乎认为这比从内存加载更昂贵,即使对于单个标量值也是如此。

这使得每次使用10x800000000x7fffffff0x3f8000000x3f000000等公共常量进行操作时都需要内存访问。好吧,将这些值编码在机器代码中将占用 4每个字节,但 32 位绝对地址或 rip- 相对地址也是如此,我相信立即加载比任何类型的内存加载都便宜。

我一直认为 movss xmm, imm32broadcastss xmm, imm32 之类的东西会很好,但一定有不做这样的指示的原因。为什么要这样设计?

【问题讨论】:

  • 相比之下,ARM NEON 确实有将立即值广播到向量中的指令。如果它们同样适用于 NEON,则作为答案发布的原因将不会令人信服。
  • 除非 SSE/AVX 设计团队的某个人看到这个问题并愿意讨论他们的想法,否则这可能无法回答。
  • 对此的标准解决方案是从内存中加载一个常量。这就是指令集的设计方式,在 MMX 和 x87 浮点单元上也是如此。
  • 这些常量中的几个(其中所有设置位在寄存器的一端都是连续的)可以在 2 条指令中生成,从 pcmped xmm0,xmm0(全一)开始。请参阅What are the best instruction sequences to generate vector constants on the fly? 和 Agner Fog 的指南。但是 2 条指令仍然比 1 条或内存源操作数差,因此编译器通常不会这样做。
  • @PeterCordes:但即使是一个字节的立即数也可能非常有用。 NEON move-immediate 只包含一个 8 位立即数(有几个不同的解码选项),这可能涵盖了 95% 的用例。

标签: assembly x86 sse instruction-set immediate-operand


【解决方案1】:

AVX(高级矢量扩展)是 x86 架构的指令集扩展,它支持使用 SIMD(单指令多数据)范例处理单精度和双精度浮点值。如您所述,AVX 不包含直接将立即值加载到寄存器中的指令。这是因为立即值通常用于可以直接在指令本身中编码的小常量,而 AVX 旨在处理更大的数据向量。

通常,从内存中加载一个值比加载一个立即值的成本更高,因为它需要额外的内存访问。但是,编译器可能会选择从内存中加载一个值,即使是对于单个标量值,如果他们认为从长远来看会更有效的话。如果该值被多次使用并且可以存储在寄存器中以供重用,或者如果该值已经存储在内存中并且可以用一条指令加载,就会发生这种情况。在这些情况下,初始内存访问的成本可能会被避免额外指令或内存访问所节省的成本所抵消。

还值得注意的是,AVX 并不是唯一支持矢量运算的指令集。其他指令集,例如 SSE(Streaming SIMD Extensions),也提供对矢量运算的支持,并且可能包括用于加载立即值的指令。这些指令集可能更适合某些类型的操作,编译器通常会根据正在编译的特定代码选择最有效的指令集。

【讨论】:

  • 这个说法其实站不住脚。手臂霓虹灯具有通过将 8 位立即数广播到适当的元素宽度来构造向量常量的指令。 (包括浮点数,其中 IIRC 立即数主要是指数位,因此您可以在一条指令中执行相当于 _mm_set1_ps( 1.0f ) 的 NEON,而无需任何内存常量。)如果您需要 16 个不同字节的东西,那么不,它不会将其嵌入指令流中是没有意义的。但是,您通常希望每个元素中的向量常量都具有相同的值。
  • AVX 建立在 SSE 之上,提供所有相同的指令。也不存在 SSE 立即常数指令。与 AVX 一样,立即数仅用于随机播放控件,例如 pshufd xmm1, xmm0, 0b00'01'02'03 以反转向量中的双字。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-12
  • 1970-01-01
  • 2017-10-28
  • 1970-01-01
  • 1970-01-01
  • 2020-08-11
  • 1970-01-01
相关资源
最近更新 更多