GHCにクラス制約のある関数を特化させるのに問題があります。私はここに私の問題の最小の例を持っています:Foo.hsとMain.hs。 2つのファイルがコンパイルされ(GHC 7.6.2、ghc -O3 Main
)、実行されます。制約による特殊化
注: Foo.hs
は削除されました。なぜ制約が必要であるかを知りたければ、もう少しコードhereを見ることができます。コードを1つのファイルに入れたり、その他のマイナーな変更を加えたりすると、GHCは単にplusFastCyc
への呼び出しをインライン展開します。 は、INLINE
とマークされていても、GHCがインライン化するには大きすぎるため、実際のコードでは発生しません。ポイントはplusFastCyc
への呼び出しではなく、インラインでそれを専門にすることです。 plusFastCyc
は実際のコードの多くの場所で呼び出されるので、GHCに強制することができても、そのような大きな関数を複製することは望ましくありません。
関心のコードはFoo.hs
でplusFastCyc
あり、ここで再現:
{-# INLINEABLE plusFastCyC#-}
{-# SPECIALIZE plusFastCyc ::
forall m . (Factored m Int) =>
(FastCyc (VT U.Vector m) Int) ->
(FastCyc (VT U.Vector m) Int) ->
(FastCyc (VT U.Vector m) Int) #-}
-- Although the next specialization makes `fcTest` fast,
-- it isn't useful to me in my real program because the phantom type M is reified
-- {-# SPECIALIZE plusFastCyc ::
-- FastCyc (VT U.Vector M) Int ->
-- FastCyc (VT U.Vector M) Int ->
-- FastCyc (VT U.Vector M) Int #-}
plusFastCyc :: (Num (t r)) => (FastCyc t r) -> (FastCyc t r) -> (FastCyc t r)
plusFastCyc (PowBasis v1) (PowBasis v2) = PowBasis $ v1 + v2
をMain.hs
ファイルは、2つのドライバがあります:〜83秒で走る〜3秒で実行vtTest
、およびfcTest
を、 forall
のd特殊化を使用して-O3でコンパイルされます。
vtTest
試験のため、付加コードがUnboxed
ベクトルに特化されているcore showsInt
オーバーSは、等、一般的なベクトルコードがfcTest
のために使用されます。 オンラインでは、GHCがplusFastCyc
の特殊バージョンを167行目の汎用バージョンと比較して書いていることがわかります。 特殊化のルールは225行目です。このルールは270行目で発生するはずです。(main6
iterate main8 y
を呼び出し、そのplusFastCyc
を専門とする場所main8
です。)
私の目標は、plusFastCyc
を専門とすることにより、早くvtTest
としてfcTest
を作ることです。 fcTest
でGHC.Exts
から
- 明示的に呼び出し
inline
:私はこれを行うには、2つの方法を見つけました。 plusFastCyc
のFactored m Int
の制約を削除します。
実際のコードベースplusFastCyc
に頻繁に使用される操作と非常大きい関数であるので、それはすべての使用でインライン化されるべきではないので、オプション1が不十分です。むしろ、GHCはplusFastCyc
の特殊バージョンを呼び出す必要があります。オプション2は実際のコードで制約が必要なため実際にはオプションではありません。
私は、INLINE
、INLINABLE
、およびSPECIALIZE
を使用してさまざまなオプションを試しましたが、何も動作しないようです。 (EDIT:例を小さくするためにplusFastCyc
を取り除いた可能性がありますので、INLINE
は関数をインライン化する可能性があります。plusFastCyc
が大きすぎるため、これは実際のコードでは起こりません。)この特定の例では、例を最小限にする前に多くのmatch_co
警告を受け取っていましたが、私はmatch_co: needs more cases
またはRULE: LHS too complicated to desugar
(およびhere)の警告を受け取りません。恐らく、 "問題"はルール内の制約であるFactored m Int
です。その制約に変更を加えると、fcTest
はvtTest
という速さで実行されます。
私は何かGHCをしていますか?なぜGHCはplusFastCyc
を専門としないのですか?それをどうすれば作れますか?
UPDATE
問題はGHC 7.8.2で解消されないので、この質問はまだ関連しています。
私は、特定の* m、すなわちMを専門に試しました。これは仕事を終わらせましたが、実際のプログラムで特定のファントムの種類を具体化することはできません。 – crockeea
私はまた、GHCバグレポートhttps://ghc.haskell.org/trac/ghc/ticket/8668を提出しましたが、問題はまだ開いています。バグ報告プロセスは私が少し質問をきれいにするのを助けました、うまくいけば、何が起こっているのか把握するのがより簡単になります。 – crockeea
@monojohnnyごめんなさい、私はあなたがそのようにフラグを立てることができると信じています。私はGHCにかなり妥当なことをするよう求めていると思います。それはできません。私はそれが間違っているかどうか、またはこれが回避策を持っている可能性のあるコンパイラの特質であるかどうかはわかりません。私は現時点で私を逃しているハッカーに関する特定のライブラリの専門化とルールの回避策を見てきたので、私自身よりもGHCの経験が豊富なコミュニティの誰かが専門化の仕方を知っていることを願っています。 – crockeea