Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

foreign import prim call to LLVM

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.

like image 206
Clinton Avatar asked Oct 31 '22 14:10

Clinton


1 Answers

I've found two problems with your code:

  1. 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!).

  2. 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
like image 118
Cactus Avatar answered Nov 15 '22 09:11

Cactus