UASM 2.49 (Linux 64bit)
.data
_r8 real8 3.141592653589793115997963468544185161590576171875
form_ db "[%.48f]",0
.code
invoke printf,addr form_, _r8
lea rdi, form_
movq xmm0,_r8
call printf
the result:
[0.000000000000000000000000000000000000000000000000][3.141592653589793115997963468544185161590576171875]
Because _r8 must pass through XMM0
40132a: 48 8d 3d b8 2d 00 00 lea 0x2db8(%rip),%rdi # 4040e9 <form_>
401331: 48 8b 35 a9 2d 00 00 mov 0x2da9(%rip),%rsi # 4040e1 <_r8>
401338: 33 c0 xor %eax,%eax
40133a: e8 01 fd ff ff callq 401040 <printf@plt>
40133f: 48 8d 3d a3 2d 00 00 lea 0x2da3(%rip),%rdi # 4040e9 <form_>
401346: f3 0f 7e 05 93 2d 00 movq 0x2d93(%rip),%xmm0 # 4040e1 <_r8>
40134d: 00
40134e: e8 ed fc ff ff callq 401040 <printf@plt>
This is a good point, and for printf it would work in Windows simply because "For vararg or unprototyped functions, any floating point values must be duplicated in the corresponding general-purpose register" (https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019). Linux does not bother with that duplication. This means that the bug may be in Windows as well, although the redundancy made it unnoticeable.
There are also differences between Windows and System V about how SSE registers are used in calling convention.
QuoteCode: [Select]
.data
_r8 real8 3.141592653589793115997963468544185161590576171875
form_ db "[%.48f]",0
.code
invoke printf,addr form_, _r8
lea rdi, form_
movq xmm0,_r8
call printf
the result:
Code: [Select]
[0.000000000000000000000000000000000000000000000000][3.141592653589793115997963468544185161590576171875]
Even though I risk being wrong at least half the time, I have to
assume that "_r8" would be a memory variable where a double precision 64-bit floating point value (i.e. a "real8") will be stored as provided in the .data segment. That value will then have a precision of 53 bits, approximately equivalent to 15 decimal digits.
That assembler must be outstanding to remember (and store) all those other additional digits provided in the source code and later retrieve them when called upon to print that "real8". :undecided:
:biggrin:
This is how VS will handle it it C, so we can see the redundancy in action:
#include <stdlib.h>
#include <stdio.h>
int main()
{
00007FF7C5B21000 sub rsp,28h
printf("[%.48lf]", 3.141592653589793115997963468544185161590576171875);
00007FF7C5B21004 movsd xmm1,mmword ptr [__real@400921fb54442d18 (07FF7C5B22170h)]
00007FF7C5B2100C lea rcx,[string "[%.48lf]" (07FF7C5B22160h)]
00007FF7C5B21013 movq rdx,xmm1
00007FF7C5B21018 call qword ptr [__imp_printf (07FF7C5B220F0h)]
return 0;
00007FF7C5B2101E xor eax,eax
}
00007FF7C5B21020 add rsp,28h
00007FF7C5B21024 ret
Output:
[3.141592653589793100000000000000000000000000000000]
Functions from the Runtime, like printf, appear to expect floating point arguments in the general purpose registers and will not bother with what the value in the SSE registers are..
#include<stdio.h>
int main()
{
printf("[%.48lf]", 3.141592653589793115997963468544185161590576171875);
return 0;
}
$ gcc -o tt.exe testcpp.cpp -m64
[3.141592653589793115997963468544185161590576171875]
0000000000001135 <main>:
1135: 55 push %rbp
1136: 48 89 e5 mov %rsp,%rbp
1139: f2 0f 10 05 d7 0e 00 movsd 0xed7(%rip),%xmm0 # 2018 <_IO_stdin_used+0x18>
1140: 00
1141: 48 8d 3d c0 0e 00 00 lea 0xec0(%rip),%rdi # 2008 <_IO_stdin_used+0x8>
1148: b8 01 00 00 00 mov $0x1,%eax
114d: e8 de fe ff ff callq 1030 <printf@plt>
1152: b8 00 00 00 00 mov $0x0,%eax
1157: 5d pop %rbp
1158: c3 retq
1159: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
:skrewy:
First 48 digits of PI
3.141592653589793238462643383279502884197169399375
3.141592653589793115997963468544185161590576171875
How Linux's printf transforms PI to NO-PI:
(https://www.dropbox.com/s/kx1lwwcaw5xjpw8/linuxPIjpg.jpg?dl=1)
Quote from: raymond on July 30, 2019, 12:26:34 PMThat assembler must be outstanding to remember (and store) all those other additional digits provided in the source code and later retrieve them when called upon to print that "real8". :undecided:
Raymond, you are right, it's a bit ridiculous. The culprit here is the CRT, print
f spits out as many digits as you want, and it doesn't bother if that is physically possible or if it's nonsense. The Internet is full of desperate programmers fighting with that feature :tongue:
Quote from: jj2007 on July 30, 2019, 08:16:43 PM
The culprit here is the CRT, printf spits out as many digits as you want, and it doesn't bother if that is physically possible or if it's nonsense.
Can you give a Windows example? I think it uses zeros, it is not the same thing as nonsense.
Quote from: AW on July 30, 2019, 08:02:38 PM
How Linux's printf transforms PI to NO-PI:
.data
_r8 real8 0.02
form_ db "[%.48f]",0
.code
fldpi
fstp _r8
lea rdi, form_
movsd xmm0,_r8
call printf
[3.141592653589793115997963468544185161590576171875].data
_r8 real8 0.1234567890123456789012345678901234567890
form_ db "[%.48f]",0
.code
lea rdi, form_
movsd xmm0,_r8
call printf
[0.123456789012345677369886232099815970286726951599