Re: Generating Function Prototypes

2002-07-04 Thread George Russell

Alistair wrote
[snip]
> ps I still think we're better off removing header files completely and
> having the Haskell type completely determine the calling convention
> employed.  But since I'm not getting any takers on that, I'll settle for
> pinning down the spec as tightly as possible.
[snip]
Perhaps I'm missing something here, but in that case how on earth is the
poor user to find out if the Haskell type really corresponds to the C type,
before the program coredumps?

I see there is a problem here in that no such check can be carried out when
the compilation is not done via C.  Would it be possible for the compiler in such
a case to spit out a C file which typechecks if and only if the Haskell and C
prototypes match, and ask gcc to typecheck it?  You could even use this approach in
all cases, then C code compiled from Haskell would never need to include
user-supplied header files.
___
FFI mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/ffi



RE: Generating Function Prototypes

2002-07-04 Thread Simon Marlow

> I just reread that section and can't see anything that contradicts the
> idea that the FFI implementation ignores any header files provided.
> For example, the phrase:
> 
>   "implements calls to C functions ... as if a function prototype for
>the called functions is in scope"
> 
> can be interpreted as meaning:
> 
> 1) Will generate code (by generating machine code directly, by
>generating C code which is then compiled, or by some other means)
>which assumes the existence of a prototype _even if the user does
>not supply one_.
> 
>[I see this as the most obvious interpretation of the phrase.]
> 
> 2) Will generate C code which #includes any header files the user has
>provided.
> 
>[I see this as a less likely interpretation but it seems to be the
>one you intend?]

Neither, I think.  You're taking an operational interpretation of that
phrase, when it is really just talking about the semantics of the call.

For example: a C function which takes a float as an argument has two
possible calling conventions: the argument may be promoted to double
(used by the C compiler when no prototype is in scope), or it may be
passed as a float (used by the C compiler when there is a prototype).
The FFI spec simply says that it is the latter calling convention that
is used.

Whether a header file is supplied or not should not affect the semantics
of the call (I'm pretty sure you agree with this, but we seem to have
lost track of this central concept somewhere along the way...).
Similarly, whether there is a prototype in scope or not should not
affect the semantics of the call.  The FFI spec doesn't say this
explicitly, but I don't think it needs to.

> My reading of the whole section is that every mention of users
> providing header files and function prototypes refers to compiling the
> C code being called not the Haskell code doing the calling.  The
> examples of using foreign import don't show the use of header files
> though the second example needs a header file to compile correctly
> with GHC.

Only when -fvia-C is on.  This is a compiler-specific issue, the FFI
doesn't need to say anything about it.

> If the intent is that any user-provided header files must be 
> obeyed, then
> I think the spec should explicitly say:
> 
>   When a header file containing a function prototype is not provided,
>   the function calling convention employed is undefined.  It may vary
>   between different operating systems, between different 
> Haskell compilers,
>   and between different functions.

This is exactly what we *don't* want - the semantics should be specified
by the FFI declaration alone, independent of any header files.  Again,
I'm sure you agree with this - but why do you think that supplying a
header file should make a difference to the semantics?

> I attach my rewording of the section.  Note that I am trying to make
> it quite clear that an ffi declaration is not portable unless you
> provide function prototypes except in the special case that your C
> compiler generates the same code with or without a prototype.

I really don't think the FFI spec needs to say anything about this at
all.  If a particular compiler requires prototypes in order to generate
correct code (such as GHC when going via C) then this is a matter for
that compiler's documentation.  Indeed, the GHC User's Guide does
mention this.

[ Heh.  Now I remember why I didn't like being able to specify header
files in the FFI declaration :-) ]

> ps I still think we're better off removing header files completely and
> having the Haskell type completely determine the calling convention
> employed.  But since I'm not getting any takers on that, I'll 
> settle for
> pinning down the spec as tightly as possible.

Aha!

I must have lost track of the discussion because I can't remember at
which point someone said that the Haskell type does not completely
specify the calling convention.

Cheers,
Simon
___
FFI mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/ffi



Re: Generating Function Prototypes

2002-07-04 Thread Alastair Reid


> Errm, shouldn't that be: [...]
> Or is there some other trick involved here?

Sorry, yes it should - just me getting confused in translating between
Haskell's

  f :: A -> B

and C's

  B f(A);

A
___
FFI mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/ffi



Re: Generating Function Prototypes

2002-07-04 Thread Ashley Yakeley

At 2002-07-04 03:55, Alastair Reid wrote:

>I still think we're better off removing header files completely and
>having the Haskell type completely determine the calling convention
>employed.

I agree. The Haskell compiler doesn't necessarily need to spit out its 
own prototypes for the benefit of the C code, but it should be able to 
compile Haskell without needing the header files. In particular, if I 
specify this:

foreign import ccall "swapHalves" swapHalves :: Int64 -> IO Int64;

...the Haskell compiler ought to call the function as if it returns a 
"long long" (or other 64-bit signed integer type).

-- 
Ashley Yakeley, Seattle WA

___
FFI mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/ffi



Re: Generating Function Prototypes

2002-07-04 Thread Malcolm Wallace

Alastair Reid <[EMAIL PROTECTED]> writes:

>   foreign import foo :: Float -> Char
> 
>   extern HsChar ffi_generated_foo(HsChar arg1);

Errm, shouldn't that be:

extern HsChar ffi_generated_foo(HsFloat arg1);
^^^
??  Or is there some other trick involved here?
Regards,
Malcolm

___
FFI mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/ffi



Re: Generating Function Prototypes

2002-07-04 Thread Alastair Reid


Alastair:
>> Well, if you disable the warning by giving gcc a consistent story,
>> then the code is correct.  (To give gcc a consistent story, don't
>> #include any user or system-supplied headers and make sure gcc
>> doesn't silently #include any of its own (as it likes to do).)

Simon:
> I don't think it's possible to completely eliminate system headers
> from the transitive closure of stuff we include when compiling a .hc
> file.  I've just taken a look at this, and it seems that while we
> can eliminate a lot of the stuff we include, there are some awkward
> ones: we need gmp.h for Integer operations, and that includes
> , and HsFFI.h needs  to get the int-type limits
> (perhaps these could be autoconf'd).

Well here's a trick that makes it ok to pull in arbitrary header files
which might appeal to the assembly post-processing fans amongst us.

Suppose you are compiling a module containing this ffi decl.

  foreign import foo :: Float -> Char
  
1) Have the Haskell compiler generate C code like this:

  #include 
  #define whatever_you_want

  extern HsChar ffi_generated_foo(HsChar arg1);

  ... put GHC-generated code here ...  


   Using the prefix "ffi_generated_" lets us be fairly confident that
   there is no prototype for the function i scope.

2) In the assembly postprocessor, apply the following transformation:

   s/ffi_generated_foo/foo/g


The only thing this will mess up is use of inline functions (which
won't get inlined).

extern inline functions (for which gcc generates no code at all) are a
bit of a problem too but the fault lies in the person who wrote the C
code for writing code which won't even compile if you turn
optimisation off.

--
Alastair
___
FFI mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/ffi



Re: Generating Function Prototypes

2002-07-04 Thread Alastair Reid


Alastair:
>> (I'm not sure that the ffi should allow compilers to vary in this
>> way but it does.)

Manuel:
> The FFI doesn't really allow compilers to emit prototypes (at least
> not in general) as this leads to semantic differences eg in argument
> promotion, for which Section 4.1.5 precisely specifies the
> behaviour.

I just reread that section and can't see anything that contradicts the
idea that the FFI implementation ignores any header files provided.
For example, the phrase:

  "implements calls to C functions ... as if a function prototype for
   the called functions is in scope"

can be interpreted as meaning:

1) Will generate code (by generating machine code directly, by
   generating C code which is then compiled, or by some other means)
   which assumes the existence of a prototype _even if the user does
   not supply one_.

   [I see this as the most obvious interpretation of the phrase.]

2) Will generate C code which #includes any header files the user has
   provided.

   [I see this as a less likely interpretation but it seems to be the
   one you intend?]

My reading of the whole section is that every mention of users
providing header files and function prototypes refers to compiling the
C code being called not the Haskell code doing the calling.  The
examples of using foreign import don't show the use of header files
though the second example needs a header file to compile correctly
with GHC.


If the intent is that any user-provided header files must be obeyed, then
I think the spec should explicitly say:

  When a header file containing a function prototype is not provided,
  the function calling convention employed is undefined.  It may vary
  between different operating systems, between different Haskell compilers,
  and between different functions.

The 'between different functions' part is because GHC #includes a lot
of header files into the code it compiles - it may well have a
prototype for the function you're calling even though you don't
provide one.  Trickier yet, gcc likes to #include some files that
aren't mentioned in any of the header files that you #include.  These
define functions like 'memmove' which gcc treates magically.

Also, I'm using 'function calling convention' instead of 'argument
passing convention' because some C compilers pass _and return_ small
structs (such as 2 ints) specially and I think you need prototypes at
both definition and call site to make the code work correctly.

I also think the wording could be changed to clearly separate the
notion of the user invoking a C compiler on a C library that they wish
to call from Haskell and the Haskell compiler invoking a C compiler as
part of its compilation process.

I attach my rewording of the section.  Note that I am trying to make
it quite clear that an ffi declaration is not portable unless you
provide function prototypes except in the special case that your C
compiler generates the same code with or without a prototype.

\subsubsection{C Argument Promotion}

The argument passing conventions of C are dependant on whether a
function prototype for the function is in scope at the site where the
function is defined and at the sites where the function is called..
%
In particular, if no function prototype is in scope, \emph{default
argument promotion} is applied to integral and floating types.

For example, consider the following C
function definition, which lacks a prototype:
%
\begin{quote}
\begin{verbatim}
void foo (a) {
  float a;
  ...
}
\end{verbatim}
\end{quote}
%
The lack of a prototype implies that a C compiler will apply default argument
promotion to the parameter \code{a}, and thus, \code{foo} will expect to
receive a value of type \code{double}, \emph{not} \code{float}.  Hence, 
any callers should call \code{foo} as though it had been defined
with type:
%
\begin{quote}
\begin{verbatim}
void foo (double a);
\end{verbatim}
\end{quote}
%
To ensure portability across different operating systems and compilers,
the user should write a header file (called \code{"header.h"}, say)
containing this prototype and should use this \code{foreign import}
declaration.
%
\begin{quote}
\begin{verbatim}
foreign import ccall "header.h" foo :: Double -> IO ()
\end{verbatim}
\end{quote}
%
(Of course, it is more reliable to use the same header file when
compiling the function being called --- but that is not always
possible.)

Just as one must be consistent in providing function prototypes 
when compiling C code, one must be consistent in providing function
prototypes when compiling Haskell code.
%
That is, when a header file containing a function prototype is not
provided and the function calling convention is affected by default
argument promotion, the function calling convention employed by
foreign function declarations is undefined.  
%
The calling convention employed may vary between different operating systems,
between different Haskell compilers, and between different functions.

A similar situation arises in th

RE: Generating Function Prototypes

2002-07-04 Thread Simon Marlow


> >> Of course, this ignores the detail that while the C compilers are
> >> generating correct code, they may also be generating warnings about
> >> alleged type errors - which can be a bit disconcerting.
> 
> > It is an error, not just a warning, if the prototypes don't match.
> > GCC will complain loudly if there's a missing 'const' - it won't
> > generate any code at all.
> 
> Well, if you disable the warning by giving gcc a consistent story,
> then the code is correct.  (To give gcc a consistent story, don't
> #include any user or system-supplied headers and make sure gcc doesn't
> silently #include any of its own (as it likes to do).)

I don't think it's possible to completely eliminate system headers from
the transitive closure of stuff we include when compiling a .hc file.
I've just taken a look at this, and it seems that while we can eliminate
a lot of the stuff we include, there are some awkward ones: we need
gmp.h for Integer operations, and that includes , and HsFFI.h
needs  to get the int-type limits (perhaps these could be
autoconf'd).

Cheers,
Simon
___
FFI mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/ffi