[GHC] #12736: Calling a complex Haskell function (obtained via FFI wrapper function) from MSVC 64-bit C code (passed in as FunPtr) can leave SSE2 registers in the XMM6-XMM15 range modified
GHC
ghc-devs at haskell.org
Tue Oct 18 21:41:22 UTC 2016
#12736: Calling a complex Haskell function (obtained via FFI wrapper function) from
MSVC 64-bit C code (passed in as FunPtr) can leave SSE2 registers in the
XMM6-XMM15 range modified
-------------------------------------+-------------------------------------
Reporter: bavism | Owner:
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 7.10.3
(FFI) |
Keywords: | Operating System: Windows
ffi,registers,sse2,clobber,xmm |
Architecture: x86_64 | Type of failure: Incorrect result
(amd64) | at runtime
Test Case: | Blocked By:
https://github.com/bavis-m/raycast |
Blocking: | Related Tickets:
Differential Rev(s): | Wiki Page:
-------------------------------------+-------------------------------------
According to the [https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
MSDN], in the Microsoft x64 architecture function calls must preserve the
SSE2 registers in the range XMM6-XMM15. The Haskell FFI can produce a
function pointer via dynamic wrapper that, when called from MSVC x64 C
code, does not preserve these registers, causing further floating-point
operations in the C code to fail.
I can reproduce this error in [https://github.com/bavis-m/raycast this
project], which is a DOOM-style raycasting engine written in Haskell, that
imports a C DLL with glue for rendering and window management. The Haskell
executable generates a FunPtr to a frame update function using the dynamic
import mechanism, and passes this to a long-lived C function that runs the
update loop. Any time this update function is called from the C loop,
subsequent floating point operations produce incorrect results (in this
case, the next operations compute a view matrix for the OpenGL window).
The output on every frame showing the view matrix should be:
{{{
viewM: 0.003125 0.000000 0.000000 -1.000000
0.000000 0.004167 0.000000 -1.000000
0.000000 0.000000 1.000000 0.000000
0.000000 0.000000 0.000000 1.000000
}}}
Running the raycaster with the Release version of the DLL causes the value
of this matrix to be corrupted. There is a patch provided (stub.patch in
the root folder) that turns the Haskell update function into an empty
stub. This causes the program to work. When stepping through the assembly
code with this patch applied, I can see in the function prologue where the
XMM registers are saved. Without the patch, these registers are not saved.
Running the Debug version does not show this error; the register
allocation must be different.
I have been attempting to create a much simpler test case to reveal this
code-generation issue, however it has been difficult. Even seemingly
trivial changes can cause the bug to not show up, it is clearly dependent
on the register allocation used internally to produce the assembly code.
Instructions for building the project are in the readme. (You will need
the Haskell Stack Tool, and Visual Studio 15).
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/12736>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list