Visual Studio 2017:_mm_load_ps经常编译为movups

问题描述 投票:5回答:1

我正在查看为我的代码生成的程序集(使用Visual Studio 2017),并注意到_mm_load_ps经常(总是?)编译为movups。

我正在使用_mm_load_ps的数据定义如下:

struct alignas(16) Vector {
    float v[4];
}

// often embedded in other structs like this
struct AABB {
    Vector min;
    Vector max;
    bool intersection(/* parameters */) const;
}

现在当我使用这个结构时,会发生以下情况:

// this code
__mm128 bb_min = _mm_load_ps(min.v);

// generates this
movups  xmm4, XMMWORD PTR [r8]

我期待movaps因为alignas(16)。在这种情况下,我还需要其他东西来说服编译器使用movaps吗?

编辑:我的问题与this question不同,因为我没有遇到任何崩溃。结构是专门对齐的,我也使用对齐分配。相反,我很好奇为什么编译器将_mm_load_ps(对齐内存的固有内容)切换到movups。如果我知道struct是在一个对齐的地址分配的,我通过这个*调用它,那么使用movaps是安全的,对吧?

c++ assembly sse intrinsics visual-studio-2017
1个回答
6
投票

在最新版本的Visual Studio和英特尔编译器(最近的2013年后?)中,编译器很少再生成对齐的SIMD加载/存储。

编译AVX或更高版本时:

  • Microsoft编译器(> VS2013?)不会生成对齐的加载。但它仍然会产生对齐的商店。
  • 英特尔编译器(> Parallel Studio 2012?)完全不再这样做了。但是你仍然可以在像memset()这样的手动优化库中的ICC编译的二进制文件中看到它们。
  • 从GCC 6.1开始,当您使用对齐的内在函数时,它仍会生成对齐的加载/存储。

允许编译器执行此操作,因为在正确编写代码时不会丢失功能。当地址对齐时,从Nehalem开始的所有处理器都不会因未对齐的加载/存储而受到惩罚。

微软在这个问题上的立场是“它不会让程序员崩溃”。不幸的是,我再也找不到微软发表此声明的原始来源了。在我看来,这与此完全相反,因为它隐藏了错位惩罚。从正确性的角度来看,它也隐藏了错误的代码。

无论如何,无条件地使用未对齐的加载/存储确实简化了编译器。

新的启示:

  • 启动Parallel Studio 2018后,英特尔编译器根本不会生成对齐的移动 - 即使对于Nehalem之前的目标也是如此。
  • 从Visual Studio 2017开始,Microsoft编译器也不再生成对齐的移动 - 即使在定位前AVX硬件时也是如此。

这两种情况都会导致旧处理器性能不可避免地降低。但似乎this is intentional作为英特尔和微软不再关心旧处理器。


唯一不受此影响的加载/存储内在函数是非临时加载/存储。没有未对齐的等价物,因此编译器别无选择。

因此,如果您只想测试代码的正确性,可以在加载/存储内在函数中替换非时间代码。但要注意不要让这样的东西进入生产代码,因为NT加载/存储(特别是NT商店)是一把双刃剑,如果你不知道你在做什么就会伤到你。

© www.soinside.com 2019 - 2024. All rights reserved.