Opened 13 years ago

Closed 12 years ago

Last modified 46 years ago

#108 closed bug (Fixed)

Header files from f.i. not propagated to non-local inlining

Reported by: nhn Owned by: nobody
Priority: normal Milestone:
Component: Compiler Version: 5.04.2
Keywords: Cc:
Operating System: Architecture:
Type of failure: Test Case:
Blocked By: Blocking:
Related Tickets: Differential Revisions:

Description

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

Attachments (1)

Evidence.2.tgz (1.0 KB) - added by nhn 13 years ago.

Download all attachments as: .zip

Change History (5)

Changed 13 years ago by nhn

comment:1 Changed 13 years ago by nhn

  • Summary changed from Returning Double from foreign fun. fails to Header files from f.i. not propagated to non-local inlining

comment:2 Changed 13 years ago by nobody

Logged In: NO 

I have also observed this bug, which also occurs when using 
the FFI directly (without any use of GreenCard).

The observation that "the inclusion 
of the header file containing the foreign function 
prototype is not propagated along with the actual 
C call" is certainly correct.  However, note that it is perfectly 
reasonable to write foreign import declarations which do not 
refer to a header file containing a C prototype, and ghc should 
still be prepared to produce correct code for this case.  

I believe that if ghc is going to do code generation via C, ghc 
must be prepared to emit its own prototype for the foreign 
function directly from the foreign import declaration, without 
requiring an external header file.


If you would like a slightly smaller test case that reproduces 
this bug without using greencard, or have further questions, 
please let me know.

-Antony
antony at apocalypse dot org

comment:3 Changed 13 years ago by simonmar

  • Summary changed from Returning Double from foreign fun. fails to Header files from f.i. not propagated to non-local inlining
Logged In: YES 
user_id=48280

Subject of bug changed to reflect the true cause of the bug.

A workaround is in progress, a fix will take longer (we don't 
intend to tackle it immediately).

comment:4 Changed 12 years ago by simonmar

  • Status changed from assigned to closed
Logged In: YES 
user_id=48280

We have installed a temporary fix for this problem, whereby 
any foreign import with a header file attached will not be 
inlined.

A more correct fix would be to propagate the header file 
correctly across module boundaries, but this is extra work 
and we don't plan to tackle it immediately.  To avoid any 
potential performance loss, use -#include instead of 
specifying header files in the foreign import declaration.
Note: See TracTickets for help on using tickets.