2016-03-05 3 views
7

Учитывая следующий код:Какая оптимизация GHC отвечает за дублирование выражений case?

{-# 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 сгенерировал в общей сложности различных путях коды , В общем случае количество кодовых путей растет экспоненциально с числом условий.

Какая оптимизация GHC ведет к такому поведению? Есть ли флаг для управления этой оптимизацией? В моем случае это создает огромный раздутый код, и делает основные дампы очень трудными для чтения из-за глубоко вложенных выражений case.

+1

Вы на 100% уверены, что это оптимизация? Я всегда думал, что оператор Core case был ограничен, чтобы выполнять одно совпадение шаблона за раз, и, таким образом, этот тип вложенных 'case' необходим при обработке нескольких шаблонов в определении. – Bakuriu

+0

О, хм, я клянусь, что он создал что-то еще без оптимизации. Но теперь, когда я пытаюсь воспроизвести, это уже не так. Позвольте мне проверить ... – bennofs

ответ

4

После некоторых исследований я обнаружил, что оптимизация, отвечающая за это, является так называемым «случайным» преобразованием, что GHC, по-видимому, используется в упростителе, поэтому его нельзя деактивировать (поскольку это необходимо для многое из того, что делает GHC, и упрощение является неотъемлемой частью конвейера оптимизации GHC).

Следующая ссылка объясняет, как случай случае приводит к дублированию: http://lambda.jstolarek.com/2013/01/taking-magic-out-of-ghc-or-tracing-compilation-by-transformation/

В частности, случай, из случая превращает это:

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 

, где внешний корпус был продублирован и помещен в ветви.

+0

Это не полностью объясняет это, я не думаю. Случай только вступает в игру, потому что 'max' и' min' являются встроенными. Я считаю, что вы могли бы прервать это, указав '{- # NOINLINE max '# -}' 'max' :: Int -> Int -> Int'' max '= max' и аналогично для' min' и используя их. – dfeuer

Смежные вопросы