【问题标题】:Type problem with CodeGenFunction/CodeGenModule with LLVM/Haskell带有 LLVM/Haskell 的 CodeGenFunction/CodeGenModule 的类型问题
【发布时间】:2011-05-18 20:37:24
【问题描述】:

一段时间以来,我一直在尝试LLVM,仅仅是因为。然而,它确实比我想象的消耗了我更多的时间。

我曾涉足 C++ 绑定,但由于显而易见的原因,我多年前离开了 C++。我尝试了 OCaml 绑定,但我不喜欢 OCaml,主要是因为构建系统繁琐,还有其他问题。

所以我被LLVM module for Haskell 卡住了,它的类型非常安全,而且感觉非常Haskell。但是文档有些欠缺,因为唯一的例子是一些 Blog 中的例子。

简而言之,我已经开始为PL/0 做一个简单的编译器。经过两天的努力,我已经做到了这一点(解析器没问题,Parsec 是我的朋友):

AST 模块

module AST where

data Statement
    = Assign String Expression
    | Call String
    | Write String
    | If Condition Statement
    | While Condition Statement
    | Begin [Statement]
    deriving (Show, Eq)

data Condition
    = Odd Expression
    | Eq Expression Expression
    | Ne Expression Expression
    | Gt Expression Expression
    | Lt Expression Expression
    | Ge Expression Expression
    | Le Expression Expression
    deriving (Show, Eq)

data Expression
    = Identifier String
    | Number Integer
    | Plus Expression Expression
    | Minus Expression Expression
    | Multiply Expression Expression
    | Divide Expression Expression
    deriving (Show, Eq)

data Block = Block {
        blockConsts :: [(String, Integer)],
        blockVars :: [String],
        blockProcs :: [Procedure],
        blockStatement :: Statement
    }
    deriving (Show, Eq)

data Procedure = Procedure String Block
    deriving (Show, Eq)

代码生成模块:

module Codegen {-(writeModule)-} where

import LLVM.Core
import AST
import Data.Int (Int64)
import Data.Word (Word8, Word32)

codegenExpr :: [(String, Value (Ptr Int64))] -> Expression -> CodeGenFunction r (Value Int64)
codegenExpr ls (Identifier s) = case lookup s ls of
    Nothing -> error $ "unknown identifier: " ++ s
    (Just v) -> load v
codegenExpr _ (Number n) = return $ valueOf $ fromIntegral n
codegenExpr ls (Plus e1 e2)     = arith ls e1 e2 iadd
codegenExpr ls (Minus e1 e2)    = arith ls e1 e2 isub
codegenExpr ls (Multiply e1 e2) = arith ls e1 e2 imul
codegenExpr ls (Divide e1 e2)   = arith ls e1 e2 idiv

arith ls e1 e2 f = do
    lhs <- codegenExpr ls e1
    rhs <- codegenExpr ls e2
    f lhs rhs

codegenCond :: [(String, Value (Ptr Int64))] -> Condition -> CodeGenFunction r (Value Bool)
codegenCond ls (Eq e1 e2) = cnd ls e1 e2 CmpEQ
codegenCond ls (Ne e1 e2) = cnd ls e1 e2 CmpNE
codegenCond ls (Gt e1 e2) = cnd ls e1 e2 CmpGT
codegenCond ls (Lt e1 e2) = cnd ls e1 e2 CmpLT
codegenCond ls (Ge e1 e2) = cnd ls e1 e2 CmpGE
codegenCond ls (Le e1 e2) = cnd ls e1 e2 CmpLE

cnd ls e1 e2 f = do
    lhs <- codegenExpr ls e1
    rhs <- codegenExpr ls e2
    cmp f lhs rhs

codegenStatement :: [(String, Value (Ptr Int64))] -> Statement -> CodeGenFunction () ()
codegenStatement ls (Assign id e) = case lookup id ls of
    Nothing -> error $ "unknown identifier: " ++ id
    (Just v) -> do
        val <- codegenExpr ls e
        store val v
codegenStatement ls (Begin stmts) = mapM_ (codegenStatement ls) stmts
codegenStatement ls (If cond s1) = do
    ifbl <- newBasicBlock
    thenbl <- newBasicBlock

    cnd <- codegenCond ls cond
    condBr cnd ifbl thenbl

    defineBasicBlock ifbl
    codegenStatement ls s1
    ret ()

    defineBasicBlock thenbl
    ret ()
codegenStatement ls (While cond s) = do
    exit <- newBasicBlock
    while <- newBasicBlock

    defineBasicBlock while
    cnd <- codegenCond ls cond
    codegenStatement ls s
    condBr cnd while exit

    defineBasicBlock exit
    ret ()

codegenBlock :: [(String, Value (Ptr Int64))] -> Block -> CodeGenModule (Function ())
codegenBlock vls (Block _ vars _ stmt) = do
    -- And here is the type error
    func <- createFunction ExternalLinkage $ do
        ls <- mapM named vars
        codegenStatement (vls ++ ls) stmt
        mapM_ (free . snd) ls
    return func
    where
        named n = do
            v <- alloca
            return (n, v)

writeModule bl file = do
    m <- newModule
    defineModule m $ codegenBlock [] bl
    writeBitcodeToFile file m

是的,有很多代码,但很完整。我得到的类型错误是这样的:

GHCi, version 7.0.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
[1 of 2] Compiling AST              ( AST.hs, interpreted )
[2 of 2] Compiling Codegen          ( Codegen.hs, interpreted )

Codegen.hs:71:13:
    No instances for (IsFunction (),
                      FunctionArgs () (CodeGenFunction () ()) (CodeGenFunction r0 ()))
      arising from a use of `createFunction'
    Possible fix:
      add instance declarations for
      (IsFunction (),
       FunctionArgs () (CodeGenFunction () ()) (CodeGenFunction r0 ()))
    In the expression: createFunction ExternalLinkage
    In a stmt of a 'do' expression:
        func <- createFunction ExternalLinkage
              $ do { ls <- mapM named vars;
                     codegenStatement (vls ++ ls) stmt;
                     mapM_ (free . snd) ls }
    In the expression:
      do { func <- createFunction ExternalLinkage
                 $ do { ls <- mapM named vars;
                        codegenStatement (vls ++ ls) stmt;
                        .... };

       return func }

正如我所说,我已经从提到的 Block 中提取了大部分示例,并且它是这样写的。我不知道如何解决这个问题。

和往常一样,我花更多的时间来满足类型检查器的要求,而不是编写新代码。

【问题讨论】:

  • 什么是行,错误信息指向?
  • 关于 LLVM 模块的几句话。出于某种原因,Haddock 遗漏了很多函数,因此您确实需要查看源代码以了解所有内容(例如向量)。此外,synthesizer-llvm 包 (haskell.org/haskellwiki/Synthesizer) 可能是 hackage 上可用的最大 LLVM 示例,因此您可能也想看看那里。
  • @Lohn L:感谢您的提示,我离开了源代码,但我错过了从模块中获取函数的函数。这是否意味着如果我想在 Haskell 中调用 Function 值,我必须自己携带它们?

标签: haskell types llvm monads


【解决方案1】:

我对 LLVM 一点也不熟悉,所以我不知道这是否有意义,但是将 codegenBlock 的类型签名从

[(String, Value (Ptr Int64))] -> Block -> CodeGenModule (Function ())

[(String, Value (Ptr Int64))] -> Block -> CodeGenModule (Function (IO ()))

满足类型检查器,因为没有实例IsFunction (),但有一个IsFunction (IO a)

【讨论】:

  • 非常感谢。我忘了 LLVM 是基于 C 的,所以任何函数都是不纯的。
【解决方案2】:

正如 hammar 所说,您的 IsFunction 调用类型不正确。 IsFunction 定义为:

class IsType a => IsFunction a where
  llvm-0.9.1.0:LLVM.Core.Type.funcType :: [TypeDesc] -> a -> TypeDesc
    -- Defined in llvm-0.9.1.0:LLVM.Core.Type

instance [incoherent] IsFirstClass a => IsFunction (VarArgs a)
  -- Defined in llvm-0.9.1.0:LLVM.Core.Type

instance [incoherent] IsFirstClass a => IsFunction (IO a)
  -- Defined in llvm-0.9.1.0:LLVM.Core.Type

instance [incoherent] (IsFirstClass a, IsFunction b) =>
                      IsFunction (a -> b)

也就是说,对于 VarArgs、对于 IO 和对于函数类型。不适用于() 类型。所以我怀疑你的意思是在类型中使用IO ()

codegenBlock :: [(String, Value (Ptr Int64))] -> Block -> CodeGenModule (Function (IO ()))    

?

【讨论】:

    猜你喜欢
    • 2013-10-19
    • 1970-01-01
    • 1970-01-01
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-29
    • 1970-01-01
    相关资源
    最近更新 更多