Page 1 of 2
[DONE] TB1.3PR1.879 Problems with float/double in X64 mode
Posted: Tue Jan 06, 2009 8:35 pm
by ABBKlaus
i´m having problems getting floats and doubles back from these TailBiten routines :
Code: Select all
ProcedureDLL.b Test_Byte()
ProcedureReturn 123
EndProcedure
ProcedureDLL.w Test_Word()
ProcedureReturn 600
EndProcedure
ProcedureDLL.l Test_Long()
ProcedureReturn 600
EndProcedure
ProcedureDLL.f Test_Float()
ProcedureReturn 600
EndProcedure
ProcedureDLL.d Test_Double()
ProcedureReturn 600
EndProcedure
ProcedureDLL.q Test_Quad()
ProcedureReturn 600
EndProcedure
ProcedureDLL.s Test_String()
ProcedureReturn "TEST"
EndProcedure
ProcedureDLL.i Test_Integer()
ProcedureReturn 600
EndProcedure
Code: Select all
Debug Test_Byte() ; 123
Debug Test_Word() ; 600
Debug Test_Long() ; 600
Debug Test_Float() ; 0.0 <- wrong
Debug Test_Double() ; 0.0 <- wrong
Debug Test_Quad() ; 600
Debug Test_String() ; TEST
Debug Test_Integer() ; 600
There are no problems when its compiled as shared dll.
Affected Versions : PureBasic4.30X64 (X86 runs fine !)
Here is the compiled lib including asm sources :
http://www.tailbite.com/downloads/float ... .30X64.zip
I already PM´d Fred and he answered this :
IMHO, it's a bug in the pbcompiler when using ProcedureDLL, as it still returns the result in ST0 instead of XMM0. I will take a look.
Posted: Wed Mar 18, 2009 2:40 pm
by lexvictory
After quite a bit of googling, I think that TailBite can fix this. (just need to figure out the string matching)
for the float, the "FLD dword " instruction needs to be changed to "MOVSD xmm0,qword" (the qword works for 600, I've not tested with a decimal place)
for the double, the "FLD qword " needs to be changed to "MOVSD xmm0,qword"
fixing it manually in the ASM works

Posted: Wed Mar 18, 2009 11:16 pm
by ABBKlaus
great news
i will try to integrate this ASAP.
Posted: Sat Mar 21, 2009 3:01 am
by lexvictory
ok, fixed it.
However, Floats seem to lose some accuracy...
changing the float to return 600.600, this happens:
Code: Select all
Debug Test_Float();600.5999755859375
Debug 600.600;600.60000000000002
I know they are never exact... but this does not seem right...
Posted: Sat Mar 21, 2009 1:16 pm
by jack
if the first number printed is a float then it's OK, as you know a float is only accurate to about 6 digits.
Posted: Sat Mar 21, 2009 1:25 pm
by lexvictory
jack wrote:as you know
Personally I dont
My programming class at Uni hasn't gone into that much detail - plus java uses double by default (and I'm not doing Computer Science)
But thanks for that info - it just seems strange that the debug is accurate but the function return isn't (presumably because I'm fooling the ASM into thinking it's putting a qword into xmm0 when it's really a dword...)
Posted: Tue Apr 07, 2009 6:45 pm
by ABBKlaus
i just tested the new feature and it didn´t work well :
Tailbiten function pdf_GetStringWidth(String$)
Code: Select all
format MS64 COFF
Public PB_pdf_GetStringWidth
Extrn SYS_FastAllocateString4
Extrn PurePDF_ipf_GetStringWidth
Extrn SYS_FreeString
section '.text' code readable executable
PB_pdf_GetStringWidth:
MOV qword [rsp+8],rcx
PS134=64
XOR rax,rax
PUSH rax
PUSH rax
SUB rsp,40
MOV rdx,[rsp+PS134+0]
LEA rcx,[rsp+40]
SUB rsp,16
CALL SYS_FastAllocateString4
ADD rsp,16
; Protected res.f
;
; res = ipf_GetStringWidth(String$)
ADD rsp,-8
PUSH qword [rsp+48]
POP rcx
ADD rsp,-8
CALL PurePDF_ipf_GetStringWidth
ADD rsp,16
FSTP dword [rsp+48]
; ProcedureReturn res
MOVSD xmm0,qword [rsp+48]
MOVSXD rax,eax
JMP _EndProcedure135
; EndProcedure
FLDZ
_EndProcedure135:
PUSH rax
MOV rcx,qword [rsp+48]
SUB rsp,32
CALL SYS_FreeString
ADD rsp,32
POP rax
ADD rsp,56
RET
pdf_GetStringWidth(String$) from PurePDF.pb (modified to work with TB!)
Code: Select all
ProcedureDLL.f pdf_GetStringWidth(String$) ;Get width of a string in the current font.
Protected res.f
res = ipf_GetStringWidth(String$)
;ProcedureReturn ipf_GetStringWidth(String$) ; <- TB won´t detect this
ProcedureReturn res
EndProcedure
Results from Example Tutorial03 StringWidth.pb :
Code: Select all
X64:
-9223372036854775808
-9223372036854775808
-9223372036854775808
-9223372036854775808
X86:
84
84
84
84
Code: Select all
;The pdf_GetStringWidth() method allows to determine the length of a string in the current font,
;which is used here to calculate the position and the width of the frame surrounding the title.
;Then colors are set (via pdf_SetDrawColor(), pdf_SetFillColor() and pdf_SetTextColor()) and the
;thickness of the line is set to 1 mm (against 0.2 by default) with pdf_SetLineWidth(). Finally,
;we output the cell (the last parameter to 1 indicates that the background must be filled).
;The method used to print the paragraphs is pdf_MultiCell(). Each time a line reaches the right
;extremity of the cell or a carriage-return character is met, a line break is issued and a new cell
;automatically created under the current one. Text is justified by default.
;Two document properties are defined: title (pdf_SetTitle()) and author (pdf_SetAuthor()).
;Properties can be viewed by two means. First is open the document directly with Acrobat Reader,
;go to the File menu, Document info, General. Second, also available from the plug-in, is click on
;the triangle just above the right scrollbar and choose Document info.
Global title.s
title="20000 Leagues Under the Seas"
Procedure Header()
pdf_SetFont("Arial","B",15)
w = pdf_GetStringWidth(title)+6
Debug w
pdf_SetX((210 - w)/2)
pdf_SetDrawColor(0,80,180)
pdf_SetFillColor(230,230,0)
pdf_SetTextColor(220,50,50)
pdf_SetLineWidth(1)
pdf_Cell(w,9,title,1,1,#PDF_ALIGN_CENTER,1)
pdf_Ln(10)
EndProcedure
Procedure footer()
pdf_SetY(-15)
pdf_SetFont("Arial","I",8)
pdf_SetTextColor(128)
txt.s = "Page " + Str(pdf_GetPageNo())
pdf_Cell(0,10,txt,0,0,#PDF_ALIGN_CENTER)
EndProcedure
Procedure ChapterTitle(num, label.s)
pdf_SetFont("Arial", "",12)
pdf_SetFillColor(200,220,255)
pdf_Cell(0,6,"Chapter " + Str(num) + " : " + label,0,1,#PDF_ALIGN_LEFT,1)
pdf_Ln(4)
EndProcedure
Procedure ChapterBody(file.s)
txt.s = ""
FileID=OpenFile(#PB_Any,file)
If FileID
l = Lof(FileID)
If l
*MemoryBuffer = AllocateMemory(l+2)
If *MemoryBuffer
l = ReadData(FileID,*MemoryBuffer,l)
txt = PeekS(*MemoryBuffer,l,#PB_Ascii)
FreeMemory(*MemoryBuffer)
EndIf
EndIf
CloseFile(FileID)
EndIf
If txt
pdf_SetFont("Times","",12)
txt=pdf_MultiCell(0,5,txt)
pdf_Cell(0,5,txt)
pdf_Ln()
pdf_SetFont("","I")
pdf_Cell(0,5,"(end of excerpt)")
EndIf
EndProcedure
Procedure PrintChapter(num,atitle.s,file.s)
pdf_AddPage()
ChapterTitle(num,atitle)
ChapterBody(file)
EndProcedure
pdf_Create()
pdf_SetProcFooter(@Footer())
pdf_SetProcHeader(@Header())
pdf_SetTitle(title)
pdf_SetAuthor("Jules Verne")
PrintChapter(1,"A RUNAWAY REEF","20k_c1.txt");
PrintChapter(2,"THE PROS And CONS","20k_c2.txt");
pdf_Save("Tutorial03 StringWidth.pdf")
Posted: Wed Apr 08, 2009 12:07 am
by lexvictory
ok, I'll have a look.
I know its not what you want, but does it work with changing the return type to a double?
Posted: Wed Apr 08, 2009 6:14 am
by lexvictory
I've tried and tried, but to no avail. We need an asm guru if we're to fix it.
I think it's safe to say that only doubles (please don't tell me they don't work either

) will work properly in x64 with PB 4.30.
Hopefully in PB 4.40 the compiler will return floats/doubles in xmm0
Posted: Wed Apr 08, 2009 9:48 pm
by ABBKlaus
no changing the return type to double does not work either
i get the same results as mentioned above.
Code: Select all
Protected w.d
pdf_SetFont("Arial","B",15)
w = pdf_GetStringWidth(title)
Debug w
if the variable w is defined as double i get -1.#IND
Posted: Wed Apr 08, 2009 9:53 pm
by Mistrel
Can you cheat by converting all return doubles to quads and then use something similar to PeekD(@Result.q)? The same could be done for floats as well.
Posted: Thu Apr 09, 2009 2:26 am
by lexvictory
modifying the ASM to return the double in rax, and adding !mov [p.v_w], qword rax in the tutorial 3 (and a similar one in pdf_GetStringWidth());
I get this:
Code: Select all
77.644622667789463
77.644622667789463
77.644622667789463
77.644622667789463
This is not really a good solution for a big userlib though...
Posted: Thu Apr 09, 2009 2:45 am
by Mistrel
lexvictory wrote:This is not really a good solution for a big userlib though...
Can you be more specific? Is it not working? I've had no problems passing floats as integers in PureBasic 32-bit and using PeekF(@Result) to read it back.
Posted: Thu Apr 09, 2009 3:04 am
by lexvictory
Userlib mod:
Code: Select all
ProcedureDLL.d pdf_GetStringWidth(String$) ;Get width of a string in the current font.
Protected res.d
res = ipf_GetStringWidth(String$)
!mov [p.v_res], qword rax;<--this has to be added after every function that returns a double
;ProcedureReturn ipf_GetStringWidth(String$) ; <- TB won´t detect this
ProcedureReturn res
EndProcedure
program mod:
Code: Select all
Procedure Header()
pdf_SetFont("Arial","B",15)
w.d = pdf_GetStringWidth(title);+6
!mov [p.v_w], qword rax;<-- here
Debug w
pdf_SetX((210 - w)/2)
pdf_SetDrawColor(0,80,180)
pdf_SetFillColor(230,230,0)
pdf_SetTextColor(220,50,50)
pdf_SetLineWidth(1)
pdf_Cell(w,9,title,1,1,#PDF_ALIGN_CENTER,1)
pdf_Ln(10)
EndProcedure
Posted: Sat Apr 11, 2009 6:32 am
by lexvictory
Well, I don't quite know whether to believe it or not, but I've completely fixed this.
Please test it. (probably best to test that the fix doesn't kick in on x86 too - I haven't tested that)
You can now do
Code: Select all
ProcedureReturn ipf_GetStringWidth(String$)
And you won't notice the difference.
On my tests, I get 84 for the sample 3 Debug
The main trouble with this was that it's
only DLL functions that have to be fixed.
After a call to a Procedure with a double/float return, PB pops the value out. However when calling userlib functions (DLL funcs) from programs, it obeys the calling convention and looks in xmm0 for the float/double.
On a side note: should Adobe Acrobat be asking me to safe the pdf when I close it? (I have the full (professional) version)
It doesn't say there's anything wrong with it (like it did when I was experimenting with the fix), but it still asks to save...