当前位置: 首页 > 知识库问答 >
问题:

在对齐与未对齐x86 SIMD指令之间进行选择

鲍国兴
2023-03-14

一般有两种类型的SIMD指令:

A、 使用对齐内存地址的,如果地址在操作数大小边界上未对齐,则会引发一般保护(#GP)异常:

movaps  xmm0, xmmword ptr [rax]
vmovaps ymm0, ymmword ptr [rax]
vmovaps zmm0, zmmword ptr [rax]

B.以及那些与未对齐的内存地址一起工作的,不会引发此类异常:

movups  xmm0, xmmword ptr [rax]
vmovups ymm0, ymmword ptr [rax]
vmovups zmm0, zmmword ptr [rax]

但我只是好奇,为什么我要开枪打自己的脚,并使用第一组的对齐内存指令呢?

共有2个答案

鲜于高明
2023-03-14

我认为使用_mm_loadu_ps_mm_load_ps之间存在微妙的区别,即使在“Intel Nehalem及更高版本(包括Silvermont及更高版本)和AMD Bulldozer及更高版本”上也会对性能产生影响。

折叠加载和另一个操作(例如乘法到一条指令)的操作只能使用load完成,而不是loaduintrinsics,除非您启用AVX编译以允许未对齐的内存操作数。

考虑以下代码

#include <x86intrin.h>
__m128 foo(float *x, float *y) {
    __m128 vx = _mm_loadu_ps(x);
    __m128 vy = _mm_loadu_ps(y);
    return vx*vy;
}

这将转换为

movups  xmm0, XMMWORD PTR [rdi]
movups  xmm1, XMMWORD PTR [rsi]
mulps   xmm0, xmm1

但是,如果使用对齐的加载内部函数(_mm_load_ps),则将其编译为

movaps  xmm0, XMMWORD PTR [rdi]
mulps   xmm0, XMMWORD PTR [rsi]

保存一条指令。但如果编译器可以使用VEX编码的加载,那么对于未对齐也只有两条指令。

vmovups xmm0, XMMWORD PTR [rsi]
vmulps  xmm0, xmm0, XMMWORD PTR [rdi]

因此,对于对齐访问,尽管在Intel Nehalem及更高版本、Silvermont及更高版本或AMD推土机及更高版本上使用指令movaps和MOUPS时,性能没有差异。

但是,在未启用AVX的情况下编译时,如果使用\u mm\u loadu\u ps和\u mm\u loadu ps内部函数,则性能可能会有所不同,如果编译器的权衡不是movaps与movups,而是movups与ALU指令之间的权衡。(当向量仅用作一件事的输入时,就会发生这种情况,否则编译器将使用加载(load)将结果放入寄存器中以供重用。)

戈安翔
2023-03-14
  • 未对齐的访问:只能使用movup/vmovup。在对齐访问案例中讨论的相同处罚(见下一篇)也适用于此。此外,跨越缓存行或虚拟页面边界的访问总是会对所有处理器造成处罚。
  • 对齐访问:
    • 在Intel Nehalem及更高版本(包括Silvermont及更高版本)和AMD Bulldozer及更高版本上:预编码后,它们以相同的确切方式对相同的操作数执行。这包括对移动消除的支持。对于获取和预编码阶段,它们为相同的操作数消耗相同的确切资源。
    • 在pre-Nehalem和Bonnell以及pre-Bulldozer上:它们被解码为不同的融合域uops和未融合域uops。movup/vmovup在管道的前端和后端消耗更多资源(最多两倍)。换句话说,movup/vmovup在延迟和/或吞吐量方面可能比movaps/vmovaps慢两倍。

    因此,如果您不关心较旧的微体系结构,那么两者在技术上是等效的。虽然如果您知道或期望数据对齐,但应该使用对齐的指令来确保数据确实对齐,而无需在代码中添加显式检查。

 类似资料:
  • 这件事我也办不到。我使用的是react和styled组件,我的对齐/对齐不起作用。 DIV-设置为flex,FLEX-方向为列DIV-标题div DIV-主体div,flex生长设置为1,以便flexbox占据容器的全部高度 现在,身体的flex项占据了整个高度(良好),我试图将内容居中在这个div的中间。我已经尝试了所有的Align/Justify组合,但都不起作用,我不知道为什么。这是我的代码

  • 在Java中,如何使用printf()对同一行的输出进行一致的左对齐和右对齐?这是所有left aligned的代码: 这是所有东西都保持对齐的输出: 相反,如果第三个元素(0.20,1.00,9.00)是正确的,那么我想要的是什么。我在上面的输出中指出“l”是左对齐的,但我希望变量在“r”所在的位置是右对齐的。如何使右边的输出(0.20,1.00,9.00)右对齐,同时使左边的输出(苹果,派,奶

  • 我试图让中的内容在中间对齐,但没有效果。我知道将列设置为2的大小不会填满12列的网格系统的空间,但我希望它无论如何都要对齐到中间。

  • 我真的很难理解有什么区别?从我的研究来看,似乎可以...和之间空格,而可以...、、和? 此外,、和这两个属性似乎是共享的。 使用其中一个比使用另一个有何不同/优势,还是仅仅是偏爱?我觉得他们都是方式相似,只是做同样的事情,有谁知道区别吗?谢谢!!

  • 我已经阅读了网格的完整指南,但仍然对两组容器属性之间的差异感到困惑,即“”与“”。 我的困惑围绕着作者的说法,即“”集在那里是因为 有时网格的总大小可能小于网格容器的大小 我认为这两种情况都适用,而不仅仅是“”集合。 有人能解释一下吗?最好使用一些图形说明作为示例。

  • 问题内容: 在斯威夫特4,结构告诉你,和一个类型。 我了解大小和步幅,但实际上不了解。 是否有 示例 显示对齐方式,与跨度有何不同,与跨度的值不同以及在何处使用跨度不正确但在对齐方式中正确? 我是否可以总是相互计算? 问题答案: 这是一个简单的示例: 该 对齐 的结构是其所有领域的最大的队列,在这种情况下,最大的和。 结构的 跨度 是将大小四舍五入为对齐的大小,此处四舍五入为的倍数。 跨度是内存中