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.