Search code examples
floating-pointx86-64ssetruncatefloating-point-conversion

Truncating an xmm floating-point register to a 64-bit register


I want to truncate a floating-point number in one of the xmm registers to a 64-bit register, as stated by the title. Below I am dividing 15.9 by 4.95. I'm printing this out and I see that result is correct (3.212121). However, when using cvtss2si to truncate this, rdi is becoming zero in some way. I have no idea why. Why does this not truncate properly when I am expecting 3 as a result? I am on macOS assembling with Clang.

    .global _main
    .text

_main:
    movsd xmm0, qword ptr [dividend + rip]
    divsd xmm0, qword ptr [divisor + rip]
    movsd [result + rip], xmm0

    lea rdi, [frm + rip]
    movsd xmm0, qword ptr [result + rip]
    mov al, 1
    and rsp, -16
    call _printf

    cvtss2si rdi, xmm0  # expecting 3, is 0
    mov rax, 0x2000001
    syscall

    .data
dividend:
    .quad 15.9
divisor:
    .quad 4.95
result:
    .quad 0.0
frm:
    .asciz "%f\n"

Solution

  • ss is scalar single precision. You're converting the low 32-bits of the double's mantissa. As a binary32 bit-pattern, that represents a small number or exactly zero. Also, if you want to truncate instead of round to nearest, use the truncating conversion (an extra t). cvttsd2si rdi, xmm0 https://www.felixcloutier.com/x86/cvttsd2si.

    Of course, xmm registers are call-clobbered in x86-64 System V, so it makes no sense to read XMM0 right after printf returns.