Returning doubles from foreign functions
can fail when optimizations (-O1) is turned on.
Things work when using the native code generator
or when compiling with -fvia-c and -O0.
I've tried on Linux (RedHat 7.3) with both GHC 5.04.1
and GHC 5.04.2.
What seems to be going on is that the inclusion
of the header file containing the foreign function
prototype is not propagated along with the actual
C call when it gets inlined. This leads to warnings
like:
/usr/local/bin/ghc-5.04.2 -c -fglasgow-exts -O1
-package lang -keep-hc-files -o Graphics/SP/M1.o -ohi
Graphics/SP/M1.hi Graphics/SP/M1.hs
Graphics/SP/M1.hc: In function `r8Hd_fast1':
Graphics/SP/M1.hc:103: warning: implicit declaration of
function `prim_foreignF4'
The original GreenCard definition looks like this
(from a file called Graphics_SP_Foreign.gc):
%fun foreignF4 :: Double -> Double
%call (double x)
%code double y;
% y = sin(x);
% printf("x = %f, y = %f\n", x, y);
%result (double y)
The GreenCard generated C code in
Graphics_SP_Foreign_stub_ffi.c
looks like this:
double prim_foreignF4(double x)
{ double y;
do { double y;
y = sin(x);
printf("x = %f, y = %f\n", x, y);
return((double)(y));} while(0);
}
and the related header file,
Graphics_SP_Foreign_stub_ffi.h:
#include <math.h>
#include "c_stuff.h"
#include "c_stuff2.h"
#include "HsFFI.h"
extern int prim_foreignF1(int x);
extern int prim_foreignF2(int x);
extern double prim_foreignF4(double x);
The GreenCard generated Haskell:
foreignF4 :: Double -> Double
foreignF4 x =
unsafePerformIO(
prim_foreignF4 x
>>= \ y ->
(return (y)))
foreign import ccall unsafe
"Graphics_SP_Foreign_stub_ffi.h prim_foreignF4"
prim_foreignF4 :: Double -> IO (Double)
Graphics_SP_Foreign.hc starts like this:
#include "Stg.h"
#include "HsBase.h"
#include "HsLang.h"
#include "Graphics_SP_Foreign_stub_ffi.h"
#include "Graphics_SP_Foreign_stub_ffi.h"
#include "Graphics_SP_Foreign_stub_ffi.h"
i.e., the header file is included properly.
and the place where prim_foreignF4 actually gets
called looks like this:
INFO_TABLE_SRT_BITMAP(s1hc_info,s1hc_ret,0,0,0,0,RET_SMALL,static
,IF_,0,0);
IFN_(s1hc_ret) {
StgDouble _B0_;
StgDouble _B3_;
FB_
_B0_=PK_DBL((W_*)(R1.p+1));
*Sp=(W_)((P_)&s1hd_info);
{
StgDouble _ccall_result;
StgDouble _ccall_arg1=_B0_;
CALLER_SAVE_SYSTEM
_ccall_result = (prim_foreignF4((_ccall_arg1)));
CALLER_RESTORE_SYSTEM
_B3_=_ccall_result;
}
ASSIGN_DBL((W_*)(Sp-2),_B3_);
Sp=Sp-3;
JMP_(ENTRY_CODE((P_)(Sp[3])));
FE_
}
This is fine. However, there is another module M1
where foreignF4 also gets called:
module Graphics.SP.M1 where
import Graphics.SP.M2
import Graphics.SP.M3
import Graphics_SP_Foreign
sp_m1 n = "Graphics.SP.M1 [\n"
++ take n' (repeat ' ') ++ "sp_m2 = " ++
sp_m2 n' ++ "\n"
++ take n' (repeat ' ') ++ "sp_m3 = " ++
sp_m3 n' ++ "\n"
++ take n' (repeat ' ') ++ "foreignF1 3 = "
++ show (foreignF1 3) ++ "\n"
++ take n' (repeat ' ') ++ "foreignF2 3 = "
++ show (foreignF2 3) ++ "\n"
++ take n' (repeat ' ') ++ "foreignF3 = "
++ show foreignF3 ++ "\n"
++ take n' (repeat ' ') ++ "foreignF4 (pi/6)
= "
++ show (foreignF4 (pi/6)) ++ "\n"
++ "]\n"
where n' = n + 4
It's .hc file starts like this:
#include "Stg.h"
#include "HsBase.h"
#include "HsLang.h"
i.e., Graphics_SP_Foreign_stub_ffi.h does not get
included.
Yet it does contain the following call to
prim_foreignF4:
II_(r8Hd_info);
IFN_(r8Hd_fast1) {
StgDouble _B0_;
StgDouble _B3_;
FB_
STK_CHK(4,(P_)&r8Hd_info,R1.p,0,Sp[-1]=(W_)((ARG_TAG(0)));
Sp=Sp-1;);
_B0_=0.5235987755982988;
Sp[-1]=(W_)((P_)&s8Kk_info);
Sp=Sp-1;
{
StgDouble _ccall_result;
StgDouble _ccall_arg1=_B0_;
CALLER_SAVE_SYSTEM
_ccall_result = (prim_foreignF4((_ccall_arg1)));
CALLER_RESTORE_SYSTEM
_B3_=_ccall_result;
}
ASSIGN_DBL((W_*)(Sp-2),_B3_);
Sp=Sp-3;
JMP_(ENTRY_CODE((P_)(Sp[3])));
FE_
}
I've attached the complete source files as well in
case you need them.
If you need further info, I'll be happy to assist.
Regards,
/Henrik