Haskell LLVM绑定 - 使用add指令引起的类型错误

时间:2013-06-05 01:20:31

标签: haskell llvm

我正在尝试开始使用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)提供任何进一步的论据,所以我有点困惑......

我看到的第二个错误与第一个错误有关(因为addv0变量对吗?)。我猜测修复第一个错误将修复第二个错误。我做错了什么导致了这些错误?

3 个答案:

答案 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不在其中任何一个。好吧,我们来看看ValueConstValue

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

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

深入探究FFILLVM.FFI.Core的别名),我们发现:

data Value
    deriving (Typeable)
type ValueRef = Ptr Value

现在我们可以假设iadd要求Value PtrConstValue Ptr类型的争论。它们之间的区别对我来说是未知的。

就个人而言,我对Haskell中的Ptr知之甚少。 编辑:鉴于这一事实,我不能说如何正确地实例化Ptr,但我下面的答案确实如此。以上所有内容仍然有效。

答案 1 :(得分:3)

user2407038提出了关于ABinOp实例的重要观点。最终,问题是iadd至少需要一个ConstValue aValue a,但它会给出两个Int32。修复是:

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

请注意,iadd个参数中只有一个必须是值,另一个可以是Int32ABinop (Value a) a (Value a)实例。

答案 2 :(得分:0)

llvm包尝试使API尽可能接近LLVM LL文件。因此,它尝试使用FlexibleInstances将所有可能的参数类型编码为一个名为“iadd”的函数。因此,您必须在任何地方添加类型注释。与之相反,我编写了llvm-extra软件包,其中'add'总是添加'Value'类型。更简单,即使是Haskell 98,几乎不需要类型注释,如果需要,您可以随时轻松地将ConstValue转换为Value。