Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding support for generating code that uses ghc calling convention #50

Open
cartazio opened this issue May 7, 2013 · 4 comments
Open

Comments

@cartazio
Copy link
Collaborator

cartazio commented May 7, 2013

it looks like it'd be quite possible to generate code that respects the ghc calling convention, and perhaps provide a safe wrapper around running the code. (while also evading the c ffi overheads!). Which would also make it easier to generate fast calling convention code for ghc at runtime! (something that matters for me)

It might require writing a CMM (c minus minus ) shim or something, but I'm happy to look into it. And it looks like it'd be relatively sane to do for 7.6, and downright easy once ghc 7.8 stabilizes.

If i can sort it out and have it sanely working, would this be something that the maintainers would be open to merging in / helping maintain? (i think the code complexity for doing so won't be that high, and only 1-2 unsafe coerces may be needed internally :) )

any feedback / thoughts would be appreciated.

@NathanHowell
Copy link
Collaborator

There is already support for arbitrary calling conventions, see callWithConv... I've also been experimenting with tagging Functions with their calling convention, see get-nats/.../Instructions.hs... I think you'd only need one unsafeCoerce to get it working end to end. If you want to hack a patch together we can get it merged in.

@cartazio
Copy link
Collaborator Author

@NathanHowell that gives part of the story, but I think theres a teeny bit more work necessary to make it essentially as fast as a pure ghc call (in the ghc calling convention case).

heres a way to hack it out without being dependent on RTS details:
for each "unlifted function type" with n arguments, hand write a cmm foreign prim that has n+1 args, the first n being the args we wish to pass along to the llvm code, and the N+1 being the function pointer we do a jump to!

we'd at least need to write a K+1 arity function for each K arity we want to support, but we could probably make do with just doing that many, ish (depending on some fiddly details of register types etc), and have a type classe wrapper for the lifted variants of this that does the right black magic. (ie we just need the ghc cmm prim to have the right arity and number of word/pointer like args, since the cmm shim won't actually touch any pointer / word like args but the last one!).

This seems like it'd be the simplest way to shim in FAST native calls using the ghc convention.
(esp since LLVM doesnt support tables next to code natively yet, else we could just throw the raw pointer thingy at ghc and it'd know what to do!)

@cartazio
Copy link
Collaborator Author

phrased differently: for the lifted word/pointer/float args, we count the number of word/pointer args, choose the cmm primop with that count, unsafe coerce that dude to the right type, and apply it to the unlifted set of args.

theres probably a few fiddly details i'm overlooking, but thats the main parts.

also would play safely with some other bits I'm forgetting probably. I'll need to test out this idea, but assuming that we can make sure ghc fully applies stuff right (which might take a smidge of template haskell, but the primops are fine).

Alternatively, we could write 1 primop who's first arg is the fun pointer, and have the llvm side code all just have a dummy first arg that gets ignored. Then for each lifted/unlifted instance we want, just have some template haskell code that handles that

@cartazio
Copy link
Collaborator Author

we could probably do either approach pretty safely using the semantics laid out here on the ghc trac wiki

http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/HaskellExecution/FunctionCalls

theres some subtlety to making sure it does the fast calling convention of how to view the args I think, and i'm totally punting on how to view the handling return values part of the story too.

maybe the best way / or at least a way that might work more robustly if other approaches don't work, is to have something like

(\ args1 ... argsn argsFunptr -> do cmmShm ) Unliftedval1 .... unlifitedvaln funpointer

or maybe i'm missing the whole point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants