c - GCC在将整数强制转换为 float 期间生成的FPU操作

标签 c gcc assembly x86-64 fpu

我想在C中的FPU上执行除法(使用整数值):

float foo;
uint32_t *ptr1, *ptr2;
foo = (float)*(ptr1) / (float)*(ptr2);

在NASM中(来自通过GCC编译的对象)具有以下表示形式:
    mov     rax, QWORD [ptr1]
    mov     eax, DWORD [rax]
    mov     eax, eax
    test    rax, rax
    js      ?_001
    pxor    xmm0, xmm0
    cvtsi2ss xmm0, rax
    jmp     ?_002

?_001:
    mov     rdx, rax
    shr     rdx, 1
    and     eax, 01H
    or      rdx, rax
    pxor    xmm0, xmm0
    cvtsi2ss xmm0, rdx
    addss   xmm0, xmm0
?_002:
    mov     rax, QWORD [ptr2]

; ... for ptr2 pattern repeats

_001下的“黑魔法”是什么意思? cvtsi2ss是否足以从整数转换为浮点数?

最佳答案

一般而言,cvtsi2ss可以解决问题-将标量整数(其他来源将其双字整数转换为单标量,但我的命名与其他 vector ins一致)为标量单(浮点数)。但它期望带符号的整数。

所以这段代码

mov     rdx, rax                                
shr     rdx, 1                                  
and     eax, 01H                                
or      rdx, rax                                
pxor    xmm0, xmm0                              
cvtsi2ss xmm0, rdx                              
addss   xmm0, xmm0  

帮助将无符号转换为带符号(请注意js跳转-如果设置了符号位,则将执行此代码-否则将被跳过)。 uint32_t的值大于0x7FFFFFFF时设置符号。

因此,“魔术”代码可以做到:
mov     rdx, rax       ; move value from ptr1 to edx                         
shr     rdx, 1         ; div by 2 - logic shift not arithmetic because ptr1 is unsigned
and     eax, 01H       ; save least significant bit                          
or      rdx, rax       ; move this bit to divided value to someway fix rounding errors                         
pxor    xmm0, xmm0                              
cvtsi2ss xmm0, rdx                              
addss   xmm0, xmm0     ; add to itself = multiply by 2

我不确定您使用什么编译器和编译选项-GCC只是简单地
cvtsi2ssq       xmm0, rbx
cvtsi2ssq       xmm1, rax
divss   xmm0, xmm1

希望对您有所帮助。

关于c - GCC在将整数强制转换为 float 期间生成的FPU操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41495498/

相关文章:

c++ - 为什么gcc/clang要用两个128bit的xmm寄存器来传递一个值?

c - Arm客户端服务器程序开发

使用arm-none-eabi-gcc编译和链接库liba.a报错

c++ - 按名称或签名计算函数调用。海合会,C++

c++ - `import` 和 `#include` 之间的区别? cpp20

assembly - 为什么在使用DIV指令之前EDX必须为0?

visual-c++ - 为什么 MSVC 不支持 AMD64 和 Itanium 目标的内联汇编?

c - Linux ps命令核心随机

c - 理解为什么 pam c api 函数 pam_get_data() 得到未初始化的值错误 "No module specific data is present "?

c - 将结构体数组作为指针传递给函数 (C)