GHC에서 자동 전문화의 전이성


392

에서 워드 프로세서 GHC 7.6에 대한 :

[Y] 당신은 종종 처음에는 SPECIALIZE pragma가 필요하지 않습니다. 모듈 M을 컴파일 할 때 GHC의 옵티 마이저 (-O 포함)는 M에 선언 된 각각의 최상위 오버로드 된 함수를 자동으로 고려하여 M에서 호출되는 다양한 유형에 특화합니다. 옵티마이 저는 가져온 각 INLINABLE 오버로드 된 함수, M에서 호출되는 다양한 유형에 특화되어 있습니다.

또한 함수 f에 대한 SPECIALIZE pragma가 주어지면 GHC는 f에 의해 호출되는 모든 type-class-loaded 함수에 대해 SPECIALIZE pragma와 동일한 모듈에 있거나 INLINABLE 인 경우 자동으로 전문화를 작성합니다. 전 이적으로.

따라서 GHC는 pragma 없이 표시된 일부 / most / all (?) 함수를 자동으로 특수화해야 하며 명시 적 pragma를 사용하면 전문화가 전이됩니다. 내 질문은 : 자동 전문화 전이인가?INLINABLE

구체적으로, 다음은 작은 예입니다.

Main.hs :

import Data.Vector.Unboxed as U
import Foo

main =
    let y = Bar $ Qux $ U.replicate 11221184 0 :: Foo (Qux Int)
        (Bar (Qux ans)) = iterate (plus y) y !! 100
    in putStr $ show $ foldl1' (*) ans

Foo.hs :

module Foo (Qux(..), Foo(..), plus) where

import Data.Vector.Unboxed as U

newtype Qux r = Qux (Vector r)
-- GHC inlines `plus` if I remove the bangs or the Baz constructor
data Foo t = Bar !t
           | Baz !t

instance (Num r, Unbox r) => Num (Qux r) where
    {-# INLINABLE (+) #-}
    (Qux x) + (Qux y) = Qux $ U.zipWith (+) x y

{-# INLINABLE plus #-}
plus :: (Num t) => (Foo t) -> (Foo t) -> (Foo t)
plus (Bar v1) (Bar v2) = Bar $ v1 + v2

GHC는 호출을 전문화 plus하지만 성능을 저하 시키는 인스턴스 는 전문화 하지 않습니다 .(+)Qux Num

그러나 명시 적 pragma

{-# SPECIALIZE plus :: Foo (Qux Int) -> Foo (Qux Int) -> Foo (Qux Int) #-}

결과 전이 워드 프로세서는 표시로 전문화, 그래서 (+)전문 및 코드는 빠른 (모두 컴파일 30 배이다 -O2). 이것이 예상되는 동작입니까? (+)명시 적 pragma를 전 이적으로 전문화 해야합니까 ?


최신 정보

7.8.2에 대한 문서는 변경되지 않았으며 동작은 동일하므로이 질문은 여전히 ​​관련이 있습니다.


33
답을 모르겠지만 다음과 관련이있는 것 같습니다 : ghc.haskell.org/trac/ghc/ticket/5928 아마도 새로운 티켓을 개설하거나 5928과 관련이 있다고 생각되면 정보를 추가 할 가치가 있습니다
jberryman

6
@jberryman 그 티켓과 내 질문 사이의 두 가지 차이점이있을 것 :의 등가 1) 티켓에 plus하지 INLINABLE 2로 표시) simonpj이 일부 티켓 코드에가는 인라인했지만, 지적의 핵심 내 예는 어떤 함수도 인라인되지 않았 음을 보여줍니다 (특히, 두 번째 Foo생성자를 제거 할 수 없었습니다 . 그렇지 않으면 GHC 인라인 된 항목).
crockeea 2019

5
아, 알았어 plus (Bar v1) = \(Bar v2)-> Bar $ v1 + v2콜 사이트에서 LHS가 완전히 적용되도록을 정의하면 어떻게됩니까 ? 인라인 된 다음 전문화가 시작됩니까?
jberryman

3
@jberryman 재미 있군요. 나는 이 질문으로이 길을 갔고이 추적 보고서로 이어졌다 . 원래 plus이러한 링크로 인해 특별히 적용 하라는 요청이 있었지만 실제로는 전문성 이 떨어 졌습니다 plus. 나는 그것에 대한 설명이 없지만 다른 질문으로 남겨 두거나이 질문에 대한 답변으로 해결되기를 바랍니다.
crockeea 2012

11
에서 ghc.haskell.org/trac/ghc/wiki/ReportABug : "의심하는 경우, 당신의 버그를보고." 당신은 기분이 나쁘지 않을 것입니다. 특히 여기에 경험이 많은 충분한 Haskeller가 귀하의 질문에 어떻게 대답해야하는지 모르기 때문입니다. 이와 같은 테스트 사례는 아마도 GHC 개발자에게 정말 가치가 있습니다. 어쨌든 행운을 빌어 요! 당신이 티켓 파일 경우 질문을 업데이트
jberryman

답변:


4

짧은 답변 :

내가 이해 한 바와 같이 질문의 요점은 다음과 같습니다.

  • "자동화는 전이 적인가?"
  • (+)가 명시 적 pragma로 전 이적으로 전문화되기를 기대해야합니까?
  • (명백히 의도 된 것) 이것은 GHC의 버그입니까? 설명서와 일치하지 않습니까?

AFAIK, 대답은 아니오입니다. 대부분 그렇습니다. 그러나 다른 방법이 있습니다.

코드 인라인 및 유형 응용 프로그램 전문화는 속도 (실행 시간)와 코드 크기 간의 균형을 유지합니다. 기본 수준은 코드를 부 풀리지 않고 속도를 높입니다. 더 철저한 수준을 선택하는 것은 SPECIALISEpragma 를 통한 프로그래머의 재량에 달려 있습니다.

설명:

옵티마이 저는 또한 가져온 각 INLINABLE 오버로드 된 함수를 고려하여 M에서 호출되는 다양한 유형에 특화합니다.

f타입 a이 타입 클래스에 의해 구속 된 타입 변수를 포함하는 함수를 가정 해 보자 C a. GHC는 기본적으로 (a) 동일한 모듈의 모든 함수 또는 (b) 가 표시된 경우 다른 응용 프로그램 을 가져 오는 다른 모듈 의 소스 코드에서 해당 유형 응용 프로그램으로 호출되는 경우 f유형 응용 프로그램 (에 a대한 대체 t) 과 관련하여 전문화 됩니다. 에서 . 따라서, 자동 전문화가 전이되지 않습니다, 그것은 단지 접촉 수입 및 호출되는 함수 소스 코드 의를 .ffINLINABLE fBINLINABLEA

귀하의 예에서 Num다음과 같이 인스턴스를 재 작성하는 경우 :

instance (Num r, Unbox r) => Num (Qux r) where
    (+) = quxAdd

quxAdd (Qux x) (Qux y) = Qux $ U.zipWith (+) x y
  • quxAdd에서 특별히 가져 오지 않았습니다 Main. Main의 인스턴스 사전을 가져오고이 Num (Qux Int)사전 quxAdd에 대한 레코드에 포함 됩니다 (+). 그러나 사전을 가져 오지만 사전에 사용 된 내용은 가져 오지 않습니다.
  • plus호출하지 않으면 의 인스턴스 사전에 레코드에 quxAdd저장된 함수를 사용합니다 . 이 사전은 호출 사이트 (에서 )에서 컴파일러에 의해 설정됩니다 .(+)Num tMain
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.