【问题标题】:Integer arithmetic on floating points浮点整数运算
【发布时间】:2013-06-12 07:43:06
【问题描述】:

我在 xmm 寄存器中有一个浮点值,我需要对其进行一些整数运算。整数算术是指位操作,如移位或按位和/或/异或。在 C++ 中,我可以编写如下内容:

float x;
int& x_i = *reinterpret_cast<int*>(&x);
x_i &= 0x7f800000
x_i >>= 23;
x_i %= 2;
x_i <<= 23;

当使用 gcc 编译时,这会将 xmm0 中的值复制到堆栈中,然后将相同的值从堆栈加载到通用寄存器 (eax),在那里进行整数运算,最后复制 eax -> 堆栈 -> xmm。

我的问题是是否有一种方法可以在不通过堆栈的情况下执行所有这些操作。 x86_64 是否有将 xmm0 的内容复制到 eax 或其他通用寄存器的指令?

编辑:问题本身在讨论期间发生了变化。最后有两句话,我都参考了Intel C++ Intrisics Reference的相应部分。

  1. 可以使用内部函数在通用寄存器和 XMM 寄存器之间移动数据(“Steaming SIMD Extensions -> Conversion Operations for Streaming SIMD Extensions”和“Steaming SIMD Extensions 2 -> Integer Intrinsics -> Integer Move Operations for流式 SIMD 扩展 2")

  2. 可以对 XMM 寄存器执行整数算术(例如位操作)操作(“Steaming SIMD Extensions 2 -> Integer Intrinsics”部分)

我对这两个主题都特别感兴趣。

【问题讨论】:

    标签: assembly x86-64 sse cpu-registers


    【解决方案1】:

    我很惊讶 gcc 完全涉及堆栈。至少对于 ELF (SysV) ABI,第一个浮点参数将通过%xmm0 中的寄存器传递。

    如果我理解正确,您希望将浮点值移动到 32 位 GPR 中以进行按位操作。您可以使用movd 指令完成此操作:

    movd %xmm0, %eax
    

    在 C 中,您可以查看汇编输出:

    #include <immintrin.h> /* or older: <xmmintrin.h> */
    ...
    unsigned int x_i;
    *((float *) & ret) = _mm_cvtss_f32(v0);
    

    你显然会用 C++ reinterpret_cast 替换这个转换。


    要写回 SSE 寄存器:movd %eax, %xmm0,它会将 %xmm0 的第 32..127 位进行零扩展。

    【讨论】:

    • 我认为 XMM 寄存器很乐意做布尔/位数学运算。他不能在那里做手术吗? (他可能不得不转而使用汇编代码来做到这一点)。
    • 感谢您的回答。我会尽快尝试。正如我所说,即使我使用 -O3 编译,GCC 实际上也会通​​过堆栈。
    • Ira Baxter:我没有找到任何用于在 xmm 寄存器中执行位操作的指令,但这并不意味着它们不存在 :-) 你知道这样做的内在函数或指令吗?
    • 布尔数学有很多内在函数:and = _mm_and_si128 shr = _mm_srli_epi32 Mod2 = and with immediate 1 shl = _mm_slli_epi32
    • @Spiros:有关详细信息,请参阅en.wikipedia.org/wiki/… 和英特尔说明手册。 (声称早期的 SSE 指令集没有整数运算;但后来的有,而且我所知道的几乎所有 Intel/AMD 芯片都有这些东西)。
    猜你喜欢
    • 2021-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-23
    • 1970-01-01
    • 1970-01-01
    • 2018-03-22
    相关资源
    最近更新 更多