lli in interpreter mode and external native libraries

Hi all,

Is there any way to support calling external libraries from interpreted code (*not* JITted code) within lli?

I am looking at the external functions implementation, and it seems just to wrap back onto its own library, looking up lli_X_... prefixed functions. It would (for obvious reasons) be incredibly useful not to be restricted to the (tiny) set of supplied functions.

Thank you in advance,
Sarah Thompson,
USRA/RIACS, NASA Ames Research Laboratory

PS: I'm attempting to extend the interpreter to implement threads (mostly working), and will shortly attempt to rip out its state handling in order to build an explicit state model checker. So far, it looks like LLVM will do very nicely, and though supporting native code external functions isn't essential for my purposes, it would be extremely useful.

Is there any way to support calling external libraries from interpreted
code (*not* JITted code) within lli?

Sure.

I am looking at the external functions implementation, and it seems just
to wrap back onto its own library, looking up lli_X_... prefixed
functions. It would (for obvious reasons) be incredibly useful not to be
restricted to the (tiny) set of supplied functions.

There are three ways to do this:

1. Ugly: teach the interpreter about every function you care about, in
    ExternalFunctions.cpp.
2. Less Ugly: refactor the interpreter to think about things in terms of
    their prototype instead of their name. All external functions of the
    same prototype use the same calling sequence. Add code for each
    prototype you care about.
3. Best: Find a "foreign function interface" library, and use that to
    interface to native code.

PS: I'm attempting to extend the interpreter to implement threads
(mostly working), and will shortly attempt to rip out its state handling
in order to build an explicit state model checker. So far, it looks like
LLVM will do very nicely, and though supporting native code external
functions isn't essential for my purposes, it would be extremely useful.

Cool!

-Chris

Chris Lattner wrote:

3. Best: Find a "foreign function interface" library, and use that to
    interface to native code.
  

This is the only option that's really usable, unfortunately, because I have no control over what code some potential user might want to model check.

I was wondering whether there might be anything in the JIT support that could be reused for this purpose?

I can't really move to using the JIT entirely because I want to replace the memory model with something that supports backtracking -- this is doable (fairly) straightforwardly with the interpreter, but it would require some very complicated transformations to the code in order to do this within the JIT environment, and it would be quite tricky to avoid subtly breaking the semantics. That kind of approach is possible, probably, but not really something I want to attack right now.

Thanks,
Sarah

Chris Lattner wrote:

3. Best: Find a "foreign function interface" library, and use that to
    interface to native code.

This is the only option that's really usable, unfortunately, because I
have no control over what code some potential user might want to model
check.

Ok.

I was wondering whether there might be anything in the JIT support that
could be reused for this purpose?

The JIT has a superset of this functionality. However, if there is JIT support for the host that you are interested in, you shouldn't have to use the interpreter at all.

I can't really move to using the JIT entirely because I want to replace
the memory model with something that supports backtracking -- this is
doable (fairly) straightforwardly with the interpreter, but it would
require some very complicated transformations to the code in order to do
this within the JIT environment, and it would be quite tricky to avoid
subtly breaking the semantics. That kind of approach is possible,
probably, but not really something I want to attack right now.

Ok. The easiest (in some senses) approach would be to do what you say above. However, you could probably arrange for a mixed approach to work. in particular, you could have the JIT dynamically compile the FFI code you need by dynamically generating the "unpack from GenericValue" code for each callee you are interested in.

-Chris

Chris Lattner wrote:

The JIT has a superset of this functionality. However, if there is JIT support for the host that you are interested in, you shouldn't have to use the interpreter at all.

For interpreting, yes, but model checking is weirder so it's greatly beneficial to be able to heavily hack an interpreter.

I can't really move to using the JIT entirely because I want to replace
the memory model with something that supports backtracking -- this is
doable (fairly) straightforwardly with the interpreter, but it would
require some very complicated transformations to the code in order to do
this within the JIT environment, and it would be quite tricky to avoid
subtly breaking the semantics. That kind of approach is possible,
probably, but not really something I want to attack right now.
    
Ok. The easiest (in some senses) approach would be to do what you say above. However, you could probably arrange for a mixed approach to work. in particular, you could have the JIT dynamically compile the FFI code you need by dynamically generating the "unpack from GenericValue" code for each callee you are interested in.
  

That's what I'm currently trying -- it looks reasonably straightforward.

Sarah

I can't really move to using the JIT entirely because I want to replace
the memory model with something that supports backtracking -- this is
doable (fairly) straightforwardly with the interpreter, but it would
require some very complicated transformations to the code in order to do
this within the JIT environment, and it would be quite tricky to avoid
subtly breaking the semantics. That kind of approach is possible,
probably, but not really something I want to attack right now.
    

Ok. The easiest (in some senses) approach would be to do what you say above. However, you could probably arrange for a mixed approach to work. in particular, you could have the JIT dynamically compile the FFI code you need by dynamically generating the "unpack from GenericValue" code for each callee you are interested in.
  

That's what I'm currently trying -- it looks reasonably straightforward.

... and, at least on 32-bit Linux, it works fine. Thanks for the help. :slight_smile:

Sarah

Cool!

-Chris