简体   繁体   English

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

[英]Context reduction stack overflow when passing a function as a formal parameter in the llvm bindings

I am trying to solve a compile time error that is occurring when I use the Haskell llvm bindings. 我试图解决当我使用Haskell llvm绑定时发生的编译时错误。

The code : 代码

-- 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 

Comentary : mSum is a monadic function which generates a the bite code for an llvm function. 注释mSum是一个mSum函数,它为llvm函数生成一个咬合代码。 The generated function is intended to take three arguments: l : the length of a array of integers; 生成的函数用于获取三个参数: l :整数数组的长度; ptr_x a pointer to the array of integers; ptr_x指向整数数组的指针; and fn a Function. fn功能。 (line 32) The generated function will loop through the elements of the array with and accumulator called sum . (第32行)生成的函数将循环遍历数组的元素,并使用称为sum累加器。 For each value, x , sum and x will be passed to the function fn . 对于每个值, xsumx将被传递给函数fn The result of that function will become the value of sum the next time through the loop. 该函数的结果将成为下一次循环的sum的值。 The final value of sum will be returned as the value of the generated function. sum的最终值将作为生成函数的值返回。

The Error : 错误

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)) $ ...;
                  .... }

Question : There are two possible questions: If I am not passing a function correctly then how to I pass a pointer to a function in LLVM? 问题 :有两个可能的问题:如果我没有正确传递函数,那么如何将指针传递给LLVM中的函数? else what do I need to do to satisfy the type checker? 否则我需要做什么来满足类型检查器?

Aside : I do not understand the working of Haskell well enough to understand why I got this error. 旁白 :我不太了解Haskell的工作,足以理解我为什么会遇到这个错误。 I also do not understand the type signature on createNamedFunction : 我也不明白createNamedFunction上的类型签名:

(IsFunction f, FunctionArgs f g (CodeGenFunction r ()))  
=> Linkage   
-> String    
-> g    -- Function body.
-> CodeGenModule (Function f)  

Oh, good grief . 哦, 好悲伤

Yes, you probably have some sort of type error. 是的,您可能有某种类型错误。 The library here is using UndecidableInstances to do some fancy type-level logic, where "fancy" means "will cause the type checker to go into an infinite loop if you're unlucky". 这里的库使用UndecidableInstances来做一些花哨的类型级逻辑,其中“花哨”意味着“如果你运气不好会导致类型检查器进入无限循环”。 You can probably guess how lucky you are at the moment. 你可能猜到你现在有多幸运。 Unfortunately, while the resulting egregious error tells us where the loop is occurring, it's not as informative as one would like about why . 不幸的是,而造成令人震惊的错误告诉我们在那里 ,循环正在发生,它不是知识性为一体的想了解为什么

Also, please note that it's entirely reasonable to not understand why you got this error. 此外,请注意,不理解为什么会出现此错误是完全合理的。 It's messy and confusing. 这是混乱和混乱。 What follows is some rough explanation and my thoughts on narrowing down the cause: 接下来是一些粗略的解释和我对缩小原因的看法:

First of all, the loop is obviously happening while calculating FunctionArgs . 首先,在计算FunctionArgs ,循环显然正在发生。 Consider the definition of the class: 考虑类的定义:

class FunctionArgs f g r | f -> g r, g r -> f where
    ...

The part after the | |后的部分 are functional dependencies , specifying that certain parameters uniquely determine others. 功能依赖 ,指定某些参数唯一地确定其他参数。 In this case, f and the combination of g and r determine each other, so it's sort of a two-way function that can compute in either direction. 在这种情况下, fgr的组合相互确定,因此它是一种双向函数,可以在任一方向上进行计算。

Your function is mSum :: CodeGenModule (Function Sig) , unifying with the signature of createNamedFunction gives us Sig as the f parameter, with r and g currently unknown. 你的函数是mSum :: CodeGenModule (Function Sig) ,与createNamedFunction的签名统一,给我们Sig作为f参数, rg目前未知。 The type synonym Sig expands to Int32 -> Ptr Int32 -> Function Acc-> IO Int32 . 类型同义词Sig扩展为Int32 -> Ptr Int32 -> Function Acc-> IO Int32 Now we can look at the instance list for FunctionArgs and see what this gives us. 现在我们可以查看FunctionArgs实例列表 ,看看它给了我们什么。

Operator precedence gives us the leftmost function arrow as the outermost type constructor for Sig , so we find the matching instance: FunctionArgs bb' r => FunctionArgs (a -> b) (Value a -> b') r . 运算符优先级给出了最左边的函数箭头作为Sig的最外层类型构造函数,因此我们找到匹配的实例: FunctionArgs bb' r => FunctionArgs (a -> b) (Value a -> b') r We can substitute in the types, do unification as needed, and repeat: 我们可以在类型中替换,根据需要进行统一,并重复:

  • 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

You should be able to match these steps up with the stack trace in the error you got. 您应该能够将这些步骤与您收到的错误中的堆栈跟踪相匹配。 One interesting thing is that there are extra steps in the stack trace that I'm not certain of the reason for--something to do with how it fills in the types based on the functional dependencies, I suppose. 一个有趣的事情是,堆栈跟踪中有额外的步骤,我不确定其原因 - 与我基于功能依赖性填充类型的方式有关,我想。 It looks like it's first selecting the instance based on the (->) type constructor, then filling in the Value a -> b type constructors for the g parameter, then doing the recursive step (in the context) before returning to unify the remaining types. 看起来它首先基于(->)类型构造函数选择实例,然后为g参数填充Value a -> b类型构造函数,然后在返回统一剩余部分之前执行递归步骤(在上下文中)类型。

Now, we know that around this point is when it goes wrong; 现在,我们知道在这一点上出现问题的时候; this can be deduced from the universal principle of stack overflows, which is that the problem is somewhere just before the stack trace starts repeating the same pattern over and over. 这可以从堆栈溢出的通用原理推断出来,即问题就在堆栈跟踪开始反复重复相同模式之前的某个地方。

For the next reduction, f is instantiated with Function Acc-> IO Int32 , while g and r remain undetermined so far (though we know they must be uniquely determined by f ). 对于下一次减少, fFunction Acc-> IO Int32实例化,而gr到目前为止仍未确定(尽管我们知道它们必须由f唯一确定)。 It's also probably a good idea to look at the definition of Function at this point: type Function a = Value (Ptr a) 它也可能是一个好主意,看看定义Function在这一点上: type Function a = Value (Ptr a)

  • FunctionArgs (Value (Ptr Acc) -> IO Int32) gr

Again, we pick the instance with a function arrow: FunctionArgs bb' r => FunctionArgs (a -> b) (Value a -> b') r 同样,我们使用函数箭头选择实例: FunctionArgs bb' r => FunctionArgs (a -> b) (Value a -> b') r

...and this is where something fishy happens, because if you compare the stack trace above, it shows (Function (...) -> ...) for the g parameter. ......这就是可疑的事情,因为如果比较上面的堆栈跟踪,它会显示g参数的(Function (...) -> ...) That technically matches given the definition of Function above, because we expected Value , which is the outermost constructor of the Function type synonym. 在技​​术上匹配给定上面Function的定义,因为我们期望Value ,它是Function类型同义词的最外层构造Function Unfortunately, we also have (Function (...) -> ...) for the f parameter, which is inconsistent, because the g parameter should have an additional Value constructor. 不幸的是,我们还为f参数设置了(Function (...) -> ...) ,这是不一致的,因为g参数应该有一个额外的Value构造函数。

After filling in the incorrect structure, it then proceeds to get stuck on the step where it should fill in the remaining type variables; 在填入不正确的结构之后,它继续卡在应该填充剩余类型变量的步骤; it appears as if the bidirectional functional dependencies cause it to bounce back and forth, repeatedly trying to unify a with Value a . 看起来好像双向功能依赖性导致它来回反复,反复尝试统一aValue a So, with type synonyms expanded, we get this: 因此,随着类型同义词的扩展,我们得到:

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

...ad infinitum. ......无限的。

At this point I'm really not sure what would have resulted in this conflict. 在这一点上,我真的不确定会导致这场冲突的原因。 The result I would expect would be a consistent instance choice of FunctionArgs (Value (Ptr Acc) -> b) (Value (Value (Ptr Acc)) -> b') r , and I can't really say why it's getting stuck the way it is. 我期望的结果将是FunctionArgs (Value (Ptr Acc) -> b) (Value (Value (Ptr Acc)) -> b') r的一致实例选择FunctionArgs (Value (Ptr Acc) -> b) (Value (Value (Ptr Acc)) -> b') r ,我无法真正说出为什么会卡住事情是这样的。

Edit : Wait, I'm being silly. 编辑 :等等,我很傻。 I misread your code at first--it's pretty clearly getting some part of the incorrect type from the inferred type of the lambda expression, which I thought was more polymorphic than it actually is. 我最初误读了你的代码 - 很明显从lambda表达式的推断类型得到了错误类型的一部分,我认为它比实际上更具多态性。 In particular, the parameter fn is given as an argument to the function call :: CallArgs fg => Function f -> g , which is what's creating the inconsistent type above. 特别是,参数fn作为函数call :: CallArgs fg => Function f -> g的参数给出call :: CallArgs fg => Function f -> g ,这就是上面创建的不一致类型。 I still don't know why it's going into an infinite loop, but at least that explains the conflict. 我仍然不知道为什么它会进入无限循环,但至少可以解释冲突。

On the assumption that the inferred type due to call is correct, the g parameter should have the type Value Int32 -> Value (Ptr Int32) -> Function Acc-> CodeGenFunction Int32 () , which means f should be Int32 -> Ptr Int32 -> Ptr Acc-> IO Int32 , as opposed to your type Sig . 假设由于call引起的推断类型是正确的, g参数应该具有类型Value Int32 -> Value (Ptr Int32) -> Function Acc-> CodeGenFunction Int32 () ,这意味着f应该是Int32 -> Ptr Int32 -> Ptr Acc-> IO Int32 ,而不是你的Sig类型。

Bolstering this is that, if you look at the IsFunction class, which is also applied to f , it expects function arguments to be primitive types like Int32 or Ptr s to primitive types, but not Value , which is what Function expands to. 支持这一点的是,如果你看一下同样适用于fIsFunction类,它期望函数参数是原始类型,如Int32Ptr s到原始类型,但不是Value ,这是Function扩展到的。

So after all that, I think your problem is just that your type Sig is slightly wrong. 毕竟,我认为你的问题只是你的Sig类型有些错误。

...welp. ...韦尔普。 Okay then. 好吧。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM