I'm trying to make a call to a foreign import prim written in LLVM, using the ideas from this post but I just keep getting segfaults. Here's what I've got currently.
In Haskell
{-# LANGUAGE GHCForeignImportPrim #-}
{-# LANGUAGE MagicHash, UnboxedTuples #-}
{-# LANGUAGE ForeignFunctionInterface, UnliftedFFITypes #-}
import GHC.Prim
foreign import prim "primllvm" primllvm :: Word# -> Word# -> (# Word#, Word# #)
And in the .ll
file
define cc10 void @primllvm(i64* %baseReg, i64* %sp, i64* %hp, i64* %buffer, i64 %length, i64 %r3, i64 %r4, i64 %r5, i64 %r6, i64* %spLim, float %f1, float %f2, float %f3, float %f4, double %d1, double %d2)
{
%fp = bitcast i64* %sp to void(i64*, i64*, i64*, i64*, i64, i64, i64, i64, i64, i64*, float, float, float, float, double, double)*
tail call cc10 void %fp(i64* %baseReg, i64* %sp, i64* %hp, i64* %buffer, i64 %length, i64 %r3, i64 %r4, i64 %r5, i64 %r6, i64* %spLim, float %f1, float %f2, float %f3, float %f4, double %d1, double %d2) noreturn;
ret void
}
In theory I think this should just return it's arguments as a tuple, but like I said, it just segfaults. Any help to get this working appreciated.
I've found two problems with your code:
Although your signature says you pass in two Word#
arguments on the Haskell side, on the LLC side you have i64* %buffer
and i64 %length
(note type of %buffer
is a pointer type!).
There is one more level of indirection in sp
: sp
points at the stack, and the top thing on the stack is the continuation pointer. Your code seems to try to interpret the stack pointer as the function pointer itself.
I don't know LLVM, I've just pieced it together by looking at the blog post you linked, knowing GHC, and playing around; so I eventually had to resort to looking at clang
's output, so there might be a more efficient way to handle #2, but anyway here is a version that works and implements swapping of two 64-bit numbers:
define cc10 void @primllvm(i64* %baseReg, i64* %sp, i64* %hp,
i64 %x, i64 %y, i64 %r3, i64 %r4, i64 %r5, i64 %r6,
i64* %spLim,
float %f1, float %f2, float %f3, float %f4,
double %d1, double %d2)
{
%1 = getelementptr inbounds i64* %sp, i64 0
%2 = load i64* %1, align 8
%cont = inttoptr i64 %2 to void (i64*, i64*, i64*,
i64, i64, i64, i64, i64, i64,
i64*,
float, float, float, float,
double, double)*
tail call cc10 void %cont(i64* %baseReg, i64* %sp, i64* %hp,
i64 %y, i64 %x, i64 %r3, i64 %r4, i64 %r5, i64 %r6,
i64* %spLim,
float %f1, float %f2, float %f3, float %f4,
double %d1, double %d2) noreturn
ret void
}
Haskell code for testing:
{-# LANGUAGE GHCForeignImportPrim #-}
{-# LANGUAGE MagicHash, UnboxedTuples, BangPatterns #-}
{-# LANGUAGE ForeignFunctionInterface, UnliftedFFITypes #-}
import GHC.Prim
import GHC.Word
foreign import prim "primllvm" primllvm :: Word# -> Word# -> (# Word#, Word# #)
main :: IO ()
main = do
let !(W# w1) = 12
!(W# w2) = 34
!(# w1', w2' #) = primllvm w1 w2
x = W# w1'
y = W# w2'
print (x, y)
Building:
llc -filetype=obj -o Define.o Define.ll
ghc --make Use.hs Define.o
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With