简体   繁体   中英

Haskell LLVM bindings - Type error arising from use of add instruction

I'm trying to get started with the haskell-llvm bindings but I'm running into compilation errors that I don't quite understand.

Code:

module ModuleMaker where

import LLVM.Core
import LLVM.FFI.Core
import Data.Int

main :: IO ()
main = do
  m <- newNamedModule "test"

  fns <- defineModule m buildMod

  writeBitcodeToFile "ModuleMaker.bc" m

  return ()

buildMod :: CodeGenModule (Function (IO Int32))
buildMod = do 
  main <- createNamedFunction ExternalLinkage "main" $ do
    addResult <- iadd (2::Int32) (3::Int32)
    ret addResult

  return main

Which results in these two errors:

ModuleMaker.hs:20:18:
    No instance for (ABinOp Int32 Int32 (v0 c0))
      arising from a use of `iadd'
    Possible fix:
      add an instance declaration for (ABinOp Int32 Int32 (v0 c0))
    In a stmt of a 'do' block:
      addResult <- iadd (2 :: Int32) (3 :: Int32)
    In the second argument of `($)', namely
      `do { addResult <- iadd (2 :: Int32) (3 :: Int32);
            ret addResult }'
    In a stmt of a 'do' block:
      main <- createNamedFunction ExternalLinkage "main"
              $ do { addResult <- iadd (2 :: Int32) (3 :: Int32);
                     ret addResult }

ModuleMaker.hs:21:5:
    No instance for (Ret (v0 c0) Int32) arising from a use of `ret'
    The type variables `v0', `c0' are ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there is a potential instance available:
      instance [overlap ok] Ret (LLVM.Core.Value a) a
        -- Defined in `llvm-3.2.0.2:LLVM.Core.Instructions'
    Possible fix: add an instance declaration for (Ret (v0 c0) Int32)
    In a stmt of a 'do' block: ret addResult
    In the second argument of `($)', namely
      `do { addResult <- iadd (2 :: Int32) (3 :: Int32);
            ret addResult }'
    In a stmt of a 'do' block:
      main <- createNamedFunction ExternalLinkage "main"
              $ do { addResult <- iadd (2 :: Int32) (3 :: Int32);
                     ret addResult }

In the first error, I see that (ABinOp Int32 Int32 is the iadd instruction specialized for Int32 , but I don't understand where (v0 c0) is coming from or what value it should be. The haskell-llvm examples I've seen don't seem to provide any further arguments to add so I'm a little confused...

The second error I see is related to the first (because of the v0 and c0 variables right?). I'm guessing that fixing the first error will fix the second. What am I doing wrong that's causing these errors?

Looking at the source, we have that iadd :: (IsInteger c, ABinOp ab (vc)) => a -> b -> CodeGenFunction r (vc) . Then, the first two arguments of iadd must be members of the typeclass ABinOp - but you already knew this, GHC told you.

I think the (v0 c0) is not the issue, I suspect. Looking at the source, ABinOp is defined as class ABinOp abc | ab -> c where class ABinOp abc | ab -> c where . The last type argument, c is automatically determined by the type-checker given any two input arguments (their types will be inferred from the types of the arguments that you feed to functions using the ABinOp constraint). This is due to the functional dependency in the class declaration. I also suspect that the second error is directly related to the first.

Now to the problem. GHC claims that no instance exists where the first two type arguments for ABinOp are Int32 ; in fact, from what I can see looking at the source, GHC is perfectly correct. The only instances of ABinOp that I see are:

instance ABinOp (Value a) (Value a) (Value a) where
    abinop _ op (Value a1) (Value a2) = buildBinOp op a1 a2

instance ABinOp (ConstValue a) (Value a) (Value a) where
    abinop _ op (ConstValue a1) (Value a2) = buildBinOp op a1 a2

instance ABinOp (Value a) (ConstValue a) (Value a) where
    abinop _ op (Value a1) (ConstValue a2) = buildBinOp op a1 a2

instance ABinOp (ConstValue a) (ConstValue a) (ConstValue a) where
    abinop cop _ (ConstValue a1) (ConstValue a2) =
        return $ ConstValue $ cop a1 a2

instance (IsConst a) => ABinOp (Value a) a (Value a) where
    abinop cop op a1 a2 = abinop cop op a1 (constOf a2)

instance (IsConst a) => ABinOp a (Value a) (Value a) where
    abinop cop op a1 a2 = abinop cop op (constOf a1) a2

Naturally your use of iadd must match one of these (unless there are more hidden somewhere). As you can see, Int32 is not in any of those. Well, lets take a look at Value and ConstValue .

newtype Value a = Value { unValue :: FFI.ValueRef }
    deriving (Show, Typeable)

newtype ConstValue a = ConstValue { unConstValue :: FFI.ValueRef }
    deriving (Show, Typeable)

Probing deeper into FFI (an alias for LLVM.FFI.Core ) we find:

data Value
    deriving (Typeable)
type ValueRef = Ptr Value

Now we can presume that iadd demands arguements of type Value Ptr or ConstValue Ptr . The difference between them is unknown to me.

Now personally, I know very little about Ptr in Haskell. edit: In light of this fact, I can't say how to properly instantiate a Ptr , but the answer below me does. All of the above still holds.

user2407038 raises an important point about the instances of ABinOp. Ultimately, the problem is that iadd needs at least one ConstValue a or Value a , but it's given two Int32 s. The fix is:

createNamedFunction ExternalLinkage "main" $ do
  addResult <- iadd (valueOf (5 :: Int32)) (5 :: Int32)
  ret addResult

Note that only one of the iadd arguments has to be a value, the other can be a straight Int32 because of the ABinop (Value a) a (Value a) instance.

The llvm package tried to make the API as close to LLVM LL files as possible. Thus it tries to encode all possible argument types into one function called 'iadd' using FlexibleInstances. As a result you have to add type annotations everywhere. In contrast to that I wrote the llvm-extra package, where 'add' always adds 'Value' types. Much simpler, even Haskell 98, almost eliminates the need for type annotations and you can always easily convert a ConstValue to Value, if needed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM