Reputation: 307
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
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