首页 文章

为什么gcc只用_mm_set_ss添加这个movss指令?

提问于
浏览
5

使用SSE考虑这两个函数:

#include <xmmintrin.h>

int ftrunc1(float f) {
    return _mm_cvttss_si32(_mm_set1_ps(f));
}

int ftrunc2(float f) {
    return _mm_cvttss_si32(_mm_set_ss(f));
}

对于任何输入,两者的行为完全相同 . 但是汇编器输出是不同的:

ftrunc1:
    pushl   %ebp
    movl    %esp, %ebp
    cvttss2si   8(%ebp), %eax
    leave
    ret

ftrunc2:
    pushl   %ebp
    movl    %esp, %ebp
    movss   8(%ebp), %xmm0
    cvttss2si   %xmm0, %eax
    leave
    ret

也就是说, ftrunc2 额外使用一个 movss 指令!

这是正常的吗?有关系吗?当你只需要设置底部元素时, _mm_set1_ps 应该优先于 _mm_set_ss 吗?


使用的编译器是GCC 4.5.2和 -O3 -msse .

2 回答

  • 0

    _mm_set_ss 直接映射到汇编指令( movss ) . 但 _mm_set1_ps 没有 .

    从我在GCC,MSVC和ICC上看到的:

    将一对一映射到汇编指令的SSE内在函数通常被视为“原样” - 黑盒子 . 因此编译器只会优化适用于整个指令本身 . 但它不会尝试进行任何需要对各个向量元素进行数据流/依赖性分析的优化 .

    _mm_set1_ps_mm_set_ps 内在函数不映射到单个指令,并且大多数编译器都处理特殊情况 . 从我上面列出的内容开始尝试对各个元素执行数据流分析优化 .


    当你把它们放在一起时,第二个例子离开了 movss ,因为编译器并不重要 . (它没有尝试"open up" _mm_set_ss 内在 . )

  • 5

    你正在遇到窥视孔优化器的怪癖 . 出于某种原因,在第一种情况下,它确定它可以将 mov 折叠到 cvttss2si 中,而在第二种情况下它会失败 . 问题是,这有关系吗?额外的移动指令几乎是免费的 - 它在指令流中占用额外的4个字节和一个额外的解码槽,但是这两个序列需要相同数量的执行槽和相同数量的加载/存储槽(这通常是通常的)事项) . 唯一可能的关键点是ifetch的4个额外字节 - 但由于ftrunc1使用10个字节而ftrunc2使用14个,因此两者都适合单个缓存行,所以你更加关注不需要的%ebp cruft(2)你用-fno-omit-frame-pointer编译? - 我的-O3包括-fomit-frame-pointer默认情况下) . 如果没有编译更大的程序并查看汇编代码,你就无法判断 .

    最重要的是,两者之间不可能存在任何可测量的速度差异......

相关问题