As noted on other occasions, the 64-bit versions of Windows have the bad habit to destroy registers xmm0 ... xmm5 in API calls, nota bene: in 32-bit code on a 64-bit OS. Since 32-bit code on 32-bit Windows does
not trash them, and many people may have relied on this benign but undocumented behaviour, there is a nice potential for bugs that come out of the blue when running the same application the first time on a 64-bit OS.
For performance reasons, MasmBasic does not preserve the xmm regs for each and every API call used, but its own algos do preserve the xmm regs.
This worked fine in general, but I ran into a strange case that needed fixing:
include \masm32\MasmBasic\MasmBasic.inc ; download the fixed version of 6 February 2015
Init
Dim MyDouble() As REAL8 ; same for QWORD
MovVal f:xmm0, "1234.5678" ; fill low quad of xmm0 with float
movlps MyDouble(0), xmm0
deb 4, "Element 0", f:xmm0, MyDouble(0)
MovVal f:xmm0, "1234.5678"
movlps MyDouble(1), xmm0 ; <<<<<<< this instruction misbehaved
deb 4, "Element 1", f:xmm0, MyDouble(1)
MovVal f:xmm0, "1234.5678"
movlps MyDouble(2), xmm0
deb 4, "Element 2", f:xmm0, MyDouble(2)
Exit
end start
Old buggy version:
Element 0
f:xmm0 1234.567800000000
MyDouble(0) 1234.567800000000
Element 1
f:xmm0 0
MyDouble(1) 0.0
Element 2
f:xmm0 1234.567800000000
MyDouble(2) 1234.567800000000The reason for this unexpected behaviour was that the simple instruction
movlps MyDouble(1), xmm0 has a nice feature under the hood: MyDouble() is a
dynamic array. When an index hits the boundary, new memory is being requested via HeapReAlloc. And that request trashed the xmm regs - all six of them. I'd like to trash Windows, but Linux doesn't seem any better, so the solution was to preserve the six regs around the HeapReAlloc call.
It works correctly from version 6 Feb 2015 onwards.