在llvm绑定中将函数作为形式参数传递时,上下文减少堆栈溢出

Joh*_*ler 4 haskell llvm

我试图解决当我使用Haskell llvm绑定时发生的编译时错误.

代码:

-- Line 14 follows
type Acc = Int32 -> Int32 -> IO Int32
type Sig = Int32 -> Ptr Int32 -> Function Acc-> IO Int32

-- [...]

-- Line 31 follows
mSum :: CodeGenModule (Function Sig)
mSum = createNamedFunction ExternalLinkage "sum" $ \l ptr_x fn ->  do
    r <- forLoop (valueOf 0) l (valueOf (0::Int32)) $ \i sum -> do
      xi <- getIndex ptr_x i
      x <- load xi
      call fn sum x
    ret r 
Run Code Online (Sandbox Code Playgroud)

注释:mSum是一个monadic函数,它为llvm函数生成一个咬合代码.生成的函数用于获取三个参数:: l整数数组的长度; ptr_x指向整数数组的指针; 和fn一个功能.(第32行)生成的函数将循环遍历数组的元素和调用的累加器sum.对于每一个值,x,sumx将被传递给函数fn.该函数的结果将成为sum下一次循环的值.sum的最终值将作为生成函数的值返回.

错误:

llvm3.hs:32:8:
Context reduction stack overflow; size = 21
Use -fcontext-stack=N to increase stack size to N
  $dFunctionArgs :: FunctionArgs
                      (Function Acc -> b17)
                      (Value (Ptr (Int32 -> Int32 -> IO Int32)) -> b'17)
                      r18
  $dFunctionArgs :: FunctionArgs
                      (Ptr (Int32 -> Int32 -> IO Int32) -> b16)
                      (Value (Function Acc) -> b'16)
                      r17

  -- [ ... ]

  $dFunctionArgs :: FunctionArgs
                      (Ptr (Int32 -> Int32 -> IO Int32) -> b4)
                      (Value (Function Acc) -> b'4)
                      r5
  $dFunctionArgs :: FunctionArgs
                      (Function Acc -> b3)
                      (Value (Ptr (Int32 -> Int32 -> IO Int32)) -> b'3)
                      r4
  $dFunctionArgs :: FunctionArgs
                      (Ptr (Int32 -> Int32 -> IO Int32) -> b2)
                      (Value (Function Acc) -> b'2)
                      r3
  $dFunctionArgs :: FunctionArgs
                      (Function Acc -> IO Int32)
                      (Function (Int32 -> Int32 -> IO Int32)
                       -> CodeGenFunction r Terminate)
                      (CodeGenFunction r0 ())
  $dFunctionArgs :: FunctionArgs
                      (Ptr a0 -> b1) (Value (Ptr Int32) -> b'1) r2
  $dFunctionArgs :: FunctionArgs
                      (Ptr Int32 -> Function Acc -> IO Int32)
                      (Value (Ptr a0)
                       -> Function (Int32 -> a0 -> IO Int32)
                       -> CodeGenFunction r Terminate)
                      (CodeGenFunction r0 ())
  $dFunctionArgs :: FunctionArgs (i0 -> b) (Value Int32 -> b') r1
  $dFunctionArgs :: FunctionArgs
                      Sig
                      (Value i0
                       -> Value (Ptr a0)
                       -> Function f0
                       -> CodeGenFunction r19 Terminate)
                      (CodeGenFunction r0 ())
In the expression: createNamedFunction ExternalLinkage "sum"
In the expression:
    createNamedFunction ExternalLinkage "sum"
  $ \ l ptr_x fn
      -> do { r <- forLoop (valueOf 0) l (valueOf (0 :: Int32))
                 $ \ i sum -> ...;
              ret r }
In an equation for `mSum':
    mSum
      = createNamedFunction ExternalLinkage "sum"
      $ \ l ptr_x fn
          -> do { r <- forLoop (valueOf 0) l (valueOf (0 :: Int32)) $ ...;
                  .... }
Run Code Online (Sandbox Code Playgroud)

问题:有两个可能的问题:如果我没有正确传递函数,那么如何将指针传递给LLVM中的函数?否则我需要做什么来满足类型检查器?

旁白:我不太了解Haskell的工作,足以理解我为什么会遇到这个错误.我也不明白类型签名createNamedFunction:

(IsFunction f, FunctionArgs f g (CodeGenFunction r ()))  
=> Linkage   
-> String    
-> g    -- Function body.
-> CodeGenModule (Function f)  
Run Code Online (Sandbox Code Playgroud)

C. *_*ann 9

哦,好悲伤.

是的,您可能有某种类型错误.这里的库UndecidableInstances用来做一些花哨的类型级逻辑,其中"花哨"意味着"如果你不走运,会导致类型检查器进入无限循环".你可能猜到你现在有多幸运.不幸的是,而造成令人震惊的错误告诉我们这里的循环正在发生,它不是知识性为一体的想了解为什么.

此外,请注意,不理解为什么会出现此错误是完全合理的.这是混乱和混乱.接下来是一些粗略的解释和我对缩小原因的看法:

首先,循环显然是在计算时发生的FunctionArgs.考虑类的定义:

class FunctionArgs f g r | f -> g r, g r -> f where
    ...
Run Code Online (Sandbox Code Playgroud)

后面的部分|功能依赖,指定某些参数唯一地确定其他参数.在这种情况下,f以及彼此的组合gr确定,所以它是一种可以在任一方向上计算的双向函数.

你的功能mSum :: CodeGenModule (Function Sig),与签名统一的createNamedFunction给我们Sig作为f参数,以rg目前未知.类型同义词Sig扩展为Int32 -> Ptr Int32 -> Function Acc-> IO Int32.现在,我们可以看一下实例列表FunctionArgs,看看这给了我们.

运算符优先级给我们最左边的函数箭头作为最外面的类型构造函数Sig,因此我们找到匹配的实例:FunctionArgs b b' r => FunctionArgs (a -> b) (Value a -> b') r.我们可以在类型中替换,根据需要进行统一,并重复:

  • FunctionArgs (Ptr Int32 -> Function Acc-> IO Int32) b' r => FunctionArgs (Int32 -> (Ptr Int32 -> Function Acc-> IO Int32)) (Value Int32 -> b') r

  • FunctionArgs (Function Acc-> IO Int32) b' r => FunctionArgs (Ptr Int32 -> (Function Acc-> IO Int32)) (Value (Ptr Int32) -> b') r

您应该能够将这些步骤与您收到的错误中的堆栈跟踪相匹配.一个有趣的事情是,堆栈跟踪中有额外的步骤,我不确定其原因 - 与我基于功能依赖性填充类型的方式有关,我想.看起来它首先根据(->)类型构造函数选择实例,然后填充参数的Value a -> b类型构造g函数,然后在返回统一其余类型之前执行递归步骤(在上下文中).

现在,我们知道在这一点上出现问题的时候; 这可以从堆栈溢出的通用原理推断出来,即问题就在堆栈跟踪开始反复重复相同模式之前的某个地方.

对于下一次减少,f实例化为Function Acc-> IO Int32,同时g并且r到目前为止仍未确定(尽管我们知道它们必须由唯一确定f).Function在这一点上看一下这个定义也许是一个好主意:type Function a = Value (Ptr a)

  • FunctionArgs (Value (Ptr Acc) -> IO Int32) g r

我们再次使用函数箭头选择实例: FunctionArgs b b' r => FunctionArgs (a -> b) (Value a -> b') r

......这是哪里有鬼发生的,因为如果你比较上面的堆栈跟踪,它显示(Function (...) -> ...)g参数.在技​​术上匹配给定Function上面的定义,因为我们期望Value,这是Function类型同义词的最外层构造函数.不幸的是,我们也有(Function (...) -> ...)f参数,这是不一致的,因为g参数应该有一个额外的Value构造函数.

在填入不正确的结构之后,它继续卡在应该填充剩余类型变量的步骤; 它看起来好像双向函数依赖使其来回反弹,多次试图统一a使用Value a.因此,随着类型同义词的扩展,我们得到:

  • FunctionArgs (Value (Ptr Acc) -> b) (Value (Ptr Acc) -> b') r
  • FunctionArgs (Ptr Acc -> b) (Value (Value (Ptr Acc)) -> b') r

......无限的.

在这一点上,我真的不确定会导致这场冲突的原因.我期望的结果将是一致的实例选择FunctionArgs (Value (Ptr Acc) -> b) (Value (Value (Ptr Acc)) -> b') r,我不能真正说出为什么它会被卡住.

编辑:等等,我很傻.我最初误读了你的代码 - 很明显从lambda表达式的推断类型得到了错误类型的一部分,我认为它比实际上更具多态性.特别是,该参数fn作为函数的参数给出call :: CallArgs f g => Function f -> g,这是创建上述不一致类型的参数.我仍然不知道为什么它会进入无限循环,但至少可以解释冲突.

在假设由于推断类型call是正确的,g参数应该有类型Value Int32 -> Value (Ptr Int32) -> Function Acc-> CodeGenFunction Int32 (),这意味着fInt32 -> Ptr Int32 -> Ptr Acc-> IO Int32,而不是你的类型Sig.

Bolstering这是说,如果你看一下IsFunction类,这也适用于f,它期望的函数参数是原始类型,如Int32Ptrs到原始类型,但不Value,这是Function扩展到.

毕竟,我认为你的问题只是你的类型Sig有点错误.

...韦尔普.好吧.

  • 哇,什么和回答!谢谢.我现在不仅知道什么是错的,如何解决它,而是为什么它发生了,它意味着什么.您逐步完成减少是非常有帮助的.我并不完全理解功能依赖性,但是你已经走了很长一段路走向启蒙之路.我知道需要进入这样一个答案的时间和想法,我想让你知道我真正感激多少.谢谢! (3认同)