Robert
Robert

Reputation: 307

x64 comparison of doubles

I am writing a toy compiler but my comparison of doubles don't evaluate as expected. The compiler should output x64 nasm assembler. The compiler does no optimisations at all yet, so the produced code might be 'iffy' at this point. I have cleaned it up enough while preserving the error.

The doubles present in my system should fit in 64 bits. At this point the compiler allocated 16 bytes for them, but if i understand things correctly this should not interfere with these instructions. If this is the case though, please let me know. The code is supposed to evaluate (1.01325 == 1.01325).

To run the code like this on a linux machine:

nasm -f elf64 -file.asm-
clang -o test runtime.o -file.o-

Some constants present in the sourcecode.

segment .data
    str1 dq 0.0
    str2 dq 101325.0
    str3 dq 101325.0

First the code usually ran on entry.

segment .text
    global main

main:
    push qword rbp           ; save rbp
    mov qword rbp, rsp       ; load rsp

I put one of the constants in the space allocated for the variable v0. I then push this value and the other constant (the same in this case) on the FP-stack.

    sub rsp, 16              ; reserve space for v0
    mov qword [rbp-16], str2

    fld qword [rbp-16]       ; push v0
    fld qword [str3]         ; push str3

I then compare them using fcomi followed by popping the two operands of the FP-stack. I then wish the branch if they are equal (i tried using jz also, producing the same result).

    fcomi st1                ; compare ST0 and ST1

    fstp  st0                ; pop ST0
    fstp  st0                ; pop ST0

    je var3                  ; jump if ==

The compiler now just loads 'true' or 'false' to the rax register based on the jump.

var4:                        ; emit false
    mov qword rax, 0
    jmp var5
var3:                        ; emit true
    mov qword rax, 1
var5:                        ; end of ==

Now, based on the value in rax, if the two doubles were ==, the code branches again. It should branch to var1 as the constants are clearly equal but it doesn't. Could someone point me in the right direction?

    cmp qword rax, 1         ; if ((101325.0 double)== (v0 double)boolean)
    jz var1
var0:                        ; else
    jmp var2
var1:                        ; then
                             ; do stuff
                             ; commented out
var2:
    mov qword rax, 0         ; return 0
    mov qword rsp, rbp       ; restore sp
    pop rbp                  ; restore fp
    ret                      ; pop & jump

Could it be that i am assuming my system uses the 'other' endian format? Please let me know if there is any additional information i should provide or if i can increase the quality of my post in any way.

Thanks

edit: As requested, here is the full code generated. The final return 1 executed is in my setup a print, but then i would have to also post the runtime i use.

[BITS 64]

extern readInt
extern readDouble
extern printInt
extern printString
extern printDouble

segment .data
    str1 dq 0.0
    str2 dq 101325.0
    str3 dq 101325.0

segment .text
    global main

main:
    push qword rbp           ; save rbp
    mov qword rbp, rsp       ; load rsp

    sub rsp, 16              ; reserve space for v0
    mov qword [rbp-16], str2

    fld qword [rbp-16]       ; push v0
    fld qword [str3]         ; push str3

    fcomi st1                ; compare ST0 and ST1

    fstp  st0                ; pop ST0
    fstp  st0                ; pop ST0

    je var3                  ; jump if ==
var4:                        ; emit false
    mov qword rax, 0
    jmp var5
var3:                        ; emit true
    mov qword rax, 1
var5:                        ; end of ==

    cmp qword rax, 1         ; if ((101325.0 double)== (v0 double)boolean)
    jz var1
var0:                        ; else
    jmp var2
var1:                        ; then
    mov qword rax, 1         ; return 1
var2:
    mov qword rax, 0         ; return 0
    mov qword rsp, rbp       ; restore sp
    pop rbp                  ; restore fp
    ret                      ; pop & jump

Upvotes: 0

Views: 127

Answers (1)

zomega
zomega

Reputation: 2316

I have debugged your code using nemiver. The bug is in this line:

mov qword [rbp-16], str2

It does not move the value of str2 (101325.0) to [rbp-16] but the address of str2. I fixed it like this:

mov qword rax, [str2]
mov qword [rbp-16], rax

It then continues until var1 as expected.

Upvotes: 1

Related Questions