我正在尝试开始使用haskell-llvm绑定,但我遇到了编译错误,我不太明白。
代码:
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
导致这两个错误:
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 }
在第一个错误中,我看到(ABinOp Int32 Int32
是专门用于iadd
的{{1}}指令,但我不明白Int32
的来源或价值是什么它应该是。我见过的haskell-llvm例子似乎没有为(v0 c0)
提供任何进一步的论据,所以我有点困惑......
我看到的第二个错误与第一个错误有关(因为add
和v0
变量对吗?)。我猜测修复第一个错误将修复第二个错误。我做错了什么导致了这些错误?
答案 0 :(得分:3)
查看来源,我们有iadd :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
。然后,iadd
的前两个参数必须是类型类ABinOp
的成员 - 但你已经知道了这一点,GHC告诉你。
我认为(v0 c0)
不是问题,我怀疑。查看来源,ABinOp
定义为class ABinOp a b c | a b -> c where
。给定任意两个输入参数的类型检查器会自动确定最后一个类型参数c
(它们的类型将从您使用ABinOp
约束提供给函数的参数类型中推断出来)。这是由于类声明中的函数依赖性。我还怀疑第二个错误与第一个错误直接相关。
现在问题。 GHC
声称ABinOp
的前两个类型参数为Int32
时,不存在任何实例;事实上,从我所看到的来源,GHC是完全正确的。我看到ABinOp
的唯一实例是:
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
当然,您对iadd
的使用必须与其中一个相匹配(除非某处隐藏更多)。正如您所看到的,Int32
不在其中任何一个。好吧,我们来看看Value
和ConstValue
。
newtype Value a = Value { unValue :: FFI.ValueRef }
deriving (Show, Typeable)
newtype ConstValue a = ConstValue { unConstValue :: FFI.ValueRef }
deriving (Show, Typeable)
深入探究FFI
(LLVM.FFI.Core
的别名),我们发现:
data Value
deriving (Typeable)
type ValueRef = Ptr Value
现在我们可以假设iadd
要求Value Ptr
或ConstValue Ptr
类型的争论。它们之间的区别对我来说是未知的。
就个人而言,我对Haskell中的Ptr
知之甚少。
编辑:鉴于这一事实,我不能说如何正确地实例化Ptr
,但我下面的答案确实如此。以上所有内容仍然有效。
答案 1 :(得分:3)
user2407038提出了关于ABinOp实例的重要观点。最终,问题是iadd
至少需要一个ConstValue a
或Value a
,但它会给出两个Int32
。修复是:
createNamedFunction ExternalLinkage "main" $ do
addResult <- iadd (valueOf (5 :: Int32)) (5 :: Int32)
ret addResult
请注意,iadd
个参数中只有一个必须是值,另一个可以是Int32
个ABinop (Value a) a (Value a)
实例。
答案 2 :(得分:0)
llvm包尝试使API尽可能接近LLVM LL文件。因此,它尝试使用FlexibleInstances将所有可能的参数类型编码为一个名为“iadd”的函数。因此,您必须在任何地方添加类型注释。与之相反,我编写了llvm-extra软件包,其中'add'总是添加'Value'类型。更简单,即使是Haskell 98,几乎不需要类型注释,如果需要,您可以随时轻松地将ConstValue转换为Value。