【问题标题】:What GHC optimization is responsible for duplicating case expressions?什么 GHC 优化负责复制 case 表达式?
【发布时间】:2016-06-19 08:04:33
【问题描述】:

给定以下代码:

{-# OPTIONS_GHC -funbox-strict-fields #-}
module Test where

data X = X !Int !Int

test (X a b) (X c d) = X (max a c) (max b d)

GHC 在使用优化编译时生成此内核(重命名以使阅读更容易):

test
test =
  \ u v ->
    case u of x { X y z ->
    case v of c { X d e ->
    case tagToEnum# (<=# y d) of _ {
      False ->
        case tagToEnum# (<=# z e) of _ {
          False -> x;
          True -> X y e
        };
      True ->
        case tagToEnum# (<=# z e) of _ {
          False -> X d z;
          True -> c
        }
    }
    }
    }

请注意 GHC 如何生成总共 4 个不同的代码路径。一般来说,代码路径的数量随着条件的数量呈指数增长。

什么 GHC 优化会导致这种行为?是否有一个标志来控制这种优化?在我的例子中,这会产生巨大的代码膨胀,并且由于深度嵌套的 case 表达式使得核心转储非常难以阅读。

【问题讨论】:

  • 您是否 100% 确定这是一种优化?我一直认为 Core 的 case 语句仅限于一次执行一个模式匹配,因此在处理定义中的多个模式时,这种嵌套的 cases 是必要的。
  • 哦,嗯,我发誓它在没有优化的情况下生成了其他东西。但现在我试图重现,它不再。让我检查一下……

标签: haskell optimization ghc


【解决方案1】:

经过一些研究,我发现对此负责的优化是所谓的“case-of-case”转换,GHC 大概在简化器中做了,所以它不能被停用(因为它是必要的GHC 所做的很多事情,而简化器是 GHC 优化管道中不可或缺的一部分)。

以下链接解释了 case 是如何导致重复的:http://lambda.jstolarek.com/2013/01/taking-magic-out-of-ghc-or-tracing-compilation-by-transformation/

具体来说,case-of-case 会变成这样:

case ( 
  case C of 
      B1 -> F1
      B2 -> F2
 ) of
    A1 -> E1
    A2 -> E2

如下:

case C of    
    B1 -> case F1 of
              A1 -> E1
              A2 -> E2
    B2 -> case F2 of
              A1 -> E1
              A2 -> E2

外壳被复制并推入分支的地方。

【讨论】:

  • 这并不能完全解释它,我不认为。 Case-of-case 仅发挥作用,因为 maxmin 是内联的。我相信你可以通过定义 {-# NOINLINE max' #-} max' :: Int -&gt; Int -&gt; Int max' = max 和类似的 min 并使用它们来中断这一点。
猜你喜欢
  • 2014-07-12
  • 1970-01-01
  • 2017-05-23
  • 2012-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-21
  • 1970-01-01
相关资源
最近更新 更多