1

I am making a compiler that compiles to x86_64 assembly, and I am trying to implement floating point math. However, I soon ran into problems because floating points are a struggle in assembly, so I am trying to practice with them, but I am finding no luck.

In this program, I want to add two floats together, compare them with another float and print a message if they are equal, but nothing is being printed.

section .data
    float1: dd 3.14
    float2: dd 5.72
    cmp_float: dd 8.86
    msg: db "Is equal!", 10, 0
    msg_len equ $-msg

section .bss
    result: resd 1

section .text
    global _start

_start:
    fld dword [float1]  ; Load float1 into FPU stack
    fld dword [float2]  ; Load float2 into FPU stack
    faddp               ; Add two top floats of the FPU stack and push back onto the FPU stack

    fcomp dword [cmp_float] ; Compare with the top value of the FPU stack

    fstsw ax            ; Store FPU status word in AX register
    sahf                ; Move AH register to FLAGS register

    je .equal
    jmp .exit
.equal:
    mov rax, 1
    mov rdi, 1
    mov rsi, msg
    mov rdx, msg_len
    syscall
.exit:
    mov rax, 60
    mov rdi, 0
    syscall
joshjkk
  • 25
  • 1
  • 4
  • 3
    See [Is floating point math broken?](https://stackoverflow.com/q/588004/547981) Has little to do with assembly. Note you should probably not use x87 anymore. Also, use a debugger to examine values. You will see that none of your values can be exactly represented as a float. – Jester Jun 21 '23 at 19:41
  • @Jester I didn't know that, thank you so much. – joshjkk Jun 21 '23 at 19:50

1 Answers1

0

I didn't know about x87 and everything, thank you @Jester, instead use SIMD (Single Instruction, Multiple Data) instructions provided by the SSE (Streaming SIMD Extensions) or AVX (Advanced Vector Extensions) instruction sets:

section .data
    number1 dd 2.5          ; First floating-point number
    number2 dd 1.3          ; Second floating-point number
    result_add dd 0.0       ; Variable to store the addition result
    result_sub dd 0.0       ; Variable to store the subtraction result
    result_mul dd 0.0       ; Variable to store the multiplication result
    result_div dd 0.0       ; Variable to store the division result

section .text
    global _start

_start:
    ; Addition
    movss xmm0, [number1]       ; Load number1 into xmm0
    movss xmm1, [number2]       ; Load number2 into xmm1
    addss xmm0, xmm1             ; Add xmm1 to xmm0
    movss [result_add], xmm0    ; Store the result

    ; Subtraction
    movss xmm0, [number1]       ; Load number1 into xmm0
    movss xmm1, [number2]       ; Load number2 into xmm1
    subss xmm0, xmm1             ; Subtract xmm1 from xmm0
    movss [result_sub], xmm0    ; Store the result

    ; Multiplication
    movss xmm0, [number1]       ; Load number1 into xmm0
    movss xmm1, [number2]       ; Load number2 into xmm1
    mulss xmm0, xmm1             ; Multiply xmm0 by xmm1
    movss [result_mul], xmm0    ; Store the result

    ; Division
    movss xmm0, [number1]       ; Load number1 into xmm0
    movss xmm1, [number2]       ; Load number2 into xmm1
    divss xmm0, xmm1             ; Divide xmm0 by xmm1
    movss [result_div], xmm0    ; Store the result

    ; ... Rest of your code

    ; Exit the program
    mov rax, 60
    mov rdi, 0
    syscall
joshjkk
  • 25
  • 1
  • 4
  • You want `subps` and `movss` for scalar operations, like `movss xmm0, [number1]` / `subss xmm0, [number2]` / `movss [result_sub], xmm0`. Look at compiler output for working examples ([How to remove "noise" from GCC/clang assembly output?](https://stackoverflow.com/q/38552116)). `movups` is a 16-byte load or store, overwriting 12 bytes past the end of `result_sub`. Your code only happens to work because you write them in the order they're laid out in memory, so your out-of-bounds writes only stepped on locations you were about to write already. – Peter Cordes Jun 21 '23 at 21:23
  • Also, use `default rel` to `[number1]` use more efficient RIP-relative addressing modes. – Peter Cordes Jun 21 '23 at 21:24
  • @PeterCordes Got it, thanks for clarifying. – joshjkk Jun 22 '23 at 09:05
  • Oops, typo in my first comment. You want `subSS` (scalar single) not `subPS` (packed single). You already figured that out, but just clarifying for future readers that was a typo. – Peter Cordes Jun 22 '23 at 12:00
  • https://godbolt.org/ can be a useful resource to see the sort of code generated by existing compilers (with good links to machine code docs). https://godbolt.org/z/dqMh3Wa5Y was from a comment I wrote recently and causes GCC to use SSE instructions – Sam Mason Jun 23 '23 at 11:50
  • @SamMason That is very helpful, thank you. – joshjkk Jun 23 '23 at 15:21