Extension to the FFI to allow macro expansions to be avoided

Fergus Henderson fjh007 at galois.com
Thu Apr 15 21:14:12 EDT 2004

On 15-Apr-2004, Sven Panne <Sven.Panne at aedion.de> wrote:
> Fergus Henderson wrote:
> >I'd rather fix GHC so that interfacing with C macros works with ghc -fasm.
> >The equivalent works fine with the Mercury implementation ("mmc --target 
> >asm"
> >generates assembler for the Mercury code and C stubs for the FFI glue),
> >so it's clearly possible.
> How does Mercury handle something like the "broken" macros we discussed 
> recently in its different back-ends?

The macros, of course, are not broken; it the handling of them by Hugs/GHC
and/or the Haskell FFI that is broken :)

In Mercury, it would look like this:

	:- module ffi_example.
        :- interface.
        :- import_module io.
        :- type window.
        :- pred wstandend(window::in, io::di, io::uo) is det.

        :- implementation.
        :- pragma foreign_decl("C", "#include <curses.h>").
        :- pragma foreign_type("C", window, "WINDOW *").
        :- pragma import(wstandend(in,di,uo), [will_not_call_mercury],

When using the "--target asm" option, which tells the Mercury compiler to
compile directly to assembler, the Mercury compiler will generate some
C glue code to handle the FFI interfacing pragmas.  The glue code calls
the wstandend() macro with a variable of type "WINDOW *" as its argument:

	#include "mercury.h"
	#include <curses.h>

	void ffi_example__wstandend_3_p_0(void *ffi_example__Arg1_1) {
		WINDOW * Arg1;

		MR_MAYBE_UNBOX_FOREIGN_TYPE(WINDOW *, ffi_example__Arg1_1,

The macro MR_MAYBE_UNBOX_FOREIGN_TYPE converts from "void *" to "WINDOW *".
If sizeof(void *) == sizeof(WINDOW *), as is the case on most
architectures, the macro will end up just doing an assignment;
but if the C type is one that doesn't fit in a void *, it will get boxed
when passed from C to Mercury and unboxed when passed from Mercury to C.

This generated C glue code will be compiled with a C compiler.

Then for any Mercury code which calls the "wstandend" Mercury procedure,
we will generate assembler code which calls the C function in our generated
glue code.

For example, if you have

        :- pred foo(window::in, io::di, io::uo) is det.
	foo(W) --> wstandend(W).

then the Mercury compiler will generate the following assembly code:
	.globl ffi_example__foo_3_p_0
		.type   ffi_example__foo_3_p_0, at function
		jmp     ffi_example__wstandend_3_p_0
		.size   ffi_example__foo_3_p_0,.Lfe5-ffi_example__foo_3_p_0

Fergus J. Henderson                 |  "I have always known that the pursuit
Galois Connections, Inc.            |  of excellence is a lethal habit"
Phone: +1 503 626 6616              |     -- the last words of T. S. Garp.

More information about the FFI mailing list