|
-fvia-c -O generates mal-typed C code (casts double via unsigned int): msg#00005lang.haskell.glasgow.bugs
Hi, Sorry this is a rather complicated bug report but I think I've tracked it down, please bear with me. :-) It involves C code, FFI and optimisations (all seem to be required). Nice. The problem shows up as a double value loosing precision when it is sent to C land and back. It's because ghc generates C code that casts the value via an unsigned word when it gets it back from C land. Attached is a small collection of modules which exhibit the problem. If I make the test case much smaller, the problem goes away. It's not too complicated code though. Some imports were hacked around and a few bits commented out to get it out of a larger library. The test program sends (-1) :: Double to C land and back and gets something rather different back. For some context, it's part of the gtk2hs bindings. It deals with a data type (GValue) on the C side that is a 'variant' type. A big union of primitive types with an enum field to say what is in the union. The code implements peek/poke for this type. The peek/poke code does the obvious thing which is a case expression on the Haskell sum-type value or the type field of the C value. In each branch of the case we make an FFI call to do the actual getting / setting: peek gvPtr = do gtype <- liftM (toEnum.fromIntegral::Word32 -> TMType) $ (\hsc_ptr -> peekByteOff hsc_ptr 0) gvPtr case gtype of TMuint -> liftM GVuint $ valueGetUInt gvPtr TMint -> liftM GVint $ valueGetInt gvPtr ... valueGetUInt, valueGetInt, etc are wrapper around FFI calls. The problem is on the peek side of things. Lets compile everything and look at the generated C code: ghc -ffi -C -O GValue.hs '-#include <glib-object.h>' -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include ghc -ffi -C -O GValueTypes.hs '-#include <glib-object.h>' -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include ghc -ffi -C -O StoreValue.hs '-#include <glib-object.h>' -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include Now ghc is clever enough to inline the trivial wrappers functions in GValueTypes.hs so that the actual C calls are made from StoreValue.hc / StoreValue.o. gcc emits some warnings when thic C code is compiled, which gives us a hint at the problem we'll find: /tmp/ghc18212.hc: In function `StoreValue_zdwpeek_entry': /tmp/ghc18212.hc:2225: warning: assignment makes integer from pointer without a cast /tmp/ghc18212.hc:2227: warning: assignment makes pointer from integer without a cast /tmp/ghc18212.hc:2267: warning: assignment discards qualifiers from pointer target type /tmp/ghc18212.hc:2269: warning: assignment makes integer from pointer without a cast /tmp/ghc18212.hc:2271: warning: assignment makes pointer from integer without a cast /tmp/ghc18212.hc:2289: warning: assignment makes integer from pointer without a cast /tmp/ghc18212.hc:2291: warning: assignment makes pointer from integer without a cast If we look at the call site: case 60: _B0_=(StgAddr)(*Sp); *Sp=(W_)((P_)&s6Vx_info); { StgDouble _ccall_result; StgAddr _ccall_arg1=_B0_; CALLER_SAVE_SYSTEM _ccall_result = (g_value_get_double((_ccall_arg1))); CALLER_RESTORE_SYSTEM _B3_=_ccall_result; } ASSIGN_DBL((W_*)(Sp-2),_B3_); Sp=Sp-2; JMP_(ENTRY_CODE((P_)(Sp[2]))); break; What is the type of _B3_ ? Well it turns out to be W_ _B3_; which I assume is a machine word. Of course this means that C will happily and silently convert the double to an unsigned int. The same _B3_ variable is in scope for all the other branches of the C switch statement, that is why gcc complains at some of the other call sites (they're casting a pointer to int or the other way round). Sadly the double case is valid C so gcc does not complain. In GValueTypes.hc we get similar code to make the ffi calls, but because they are in separate functions there, they each get their own _B3_ variable of the right local type. It is only because of optimisations that the ffi calls have been moved together into one big switch statement and the _B3_ variable has been moved outside of each case branch that we get the problem. It might work if each branch got its own _B3_ variable or if all the assignments to/from it were cast appropriately so that C does not perform any implicit promotion / narrowing. Duncan
Glasgow-haskell-bugs mailing list Glasgow-haskell-bugs@xxxxxxxxxxx http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs
|
|
| <Prev in Thread] | Current Thread | [Next in Thread> |
|---|---|---|
| Previous by Date: | Return signatures in case expressions, Volodimir Rudenko |
|---|---|
| Next by Date: | Re: -fvia-c -O generates mal-typed C code (casts double via unsigned int), Duncan Coutts |
| Previous by Thread: | Return signatures in case expressions, Volodimir Rudenko |
| Next by Thread: | Re: -fvia-c -O generates mal-typed C code (casts double via unsigned int), Duncan Coutts |
| Indexes: | [Date] [Thread] [Top] [All Lists] |
| News | FAQ | advertise |