With help from Reid Barton in questions here and here I discovered it’s pretty easy to call assembly from GHC haskell with minimal overhead, so I cleaned up an example of this technique and posted it here:
This is especially useful if you want to return multiple values from a foreign procedure, where otherwise with the traditional FFI approach you would have to do some allocation and stuff the values into a struct or something. I find the above more understandable in any case.
Here’s an example of the dumped ASM from the
Main in the example above:
... call newCAF addq $8,%rsp testq %rax,%rax je _c73k _c73j: movq $stg_bh_upd_frame_info,-16(%rbp) movq %rax,-8(%rbp) movq $block_info,-24(%rbp) movl $4,%edi movl $3,%esi movl $2,%r14d movl $1,%ebx addq $-24,%rbp jmp sipRound_s_x3 _c73z: movq $104,904(%r13) movq $block_info,-32(%rbp) movq %r14,-24(%rbp) movq %rsi,-16(%rbp) movq %rdi,-8(%rbp) movq %rbx,(%rbp) addq $-32,%rbp ...
You can see we just prepare argument registers, do whatever with the stack pointer, do a jump, and then push the return values onto the stack. For my purposes this was almost too much overhead to make this worthwhile (you can look at notes in the code).
I thought about sketching out a ghc proposal about a way to formalize this, maybe make it safer, and maybe somehow more efficient but I don’t have the time right now and don’t really have the expertise to know if this is even a good idea or how it could work.