Haskell LLVM bindings - type error that occurs when using the add command

I am trying to start with haskell-llvm bindings, but I am facing 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 

This leads to the following 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 an (ABinOp Int32 Int32 - iadd instruction, but I don’t understand where it comes from (v0 c0) or what value it should be. The haskell-llvm examples that I saw do not seem to give no extra add arguments, so I'm a little confused ...

The second error that I see is related to the first (due to the variables v0 and c0 )?). I assume that fixing the first error will fix the second. What am I doing wrong that causes these errors?

+4
source share
3 answers

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

I think (v0 c0) not a problem, I suspect. Considering the source, ABinOp is defined as class ABinOp abc | ab -> c where class ABinOp abc | ab -> c where . The argument of the last type c automatically determined by the type checking method taking into account any two input arguments (their types will be inferred from the types of arguments that you pass to the 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 the instance does not exist, where the first two type arguments for ABinOp are Int32 ; in fact, from what I see looking at the source, the GHC is absolutely right. The only ABinOp instances 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 them (unless it is hidden somewhere else). As you can see, Int32 not included in any of them. Well, let's 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) 

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

 data Value deriving (Typeable) type ValueRef = Ptr Value 

Now we can assume that iadd requires statements like 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 cannot say how to create an instance of Ptr , but the answer below does me. All of the above is still in progress.

+3
source

user2407038 brings up an important point regarding ABinOp instances. Ultimately, the problem is that iadd needs at least one ConstValue a or Value a , but it gave two Int32 s. Correction:

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

Note that only one of the iadd arguments must be a value, the other can be direct Int32 due to an instance of ABinop (Value a) a (Value a) .

+3
source

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

0
source

Source: https://habr.com/ru/post/1484545/


All Articles