7.3. 最適化 (コードの改善)

-O* オプションば便利な最適化フラグの「詰め合わせ」を指定するのに使います. 個別の 最適化を有効/無効にするには,後述する -f* オプションを使います. マシン固有 の最適化を有効/無効にするには -m* オプションを使います.

こうしたオプションのほとんどは,オプションをオン/オフする論理値になっています(オフにする場合は no- が前置されます). -fspecialise は特定化を有効にし,-fno-specialise は無効にします. 同じオプションに関して複数のフラグが1つのコマンドラインにあらわれたときは左から右への順で評価されますので, -fno-specialise -fspecialise という指定では,特定化は有効になります.

-O* という型のフラグは大まかにいって -f* という型のフラグの組み合わせを指定しているものになっているということに注意をしてください. したがって -O* フラグと -f* フラグの効果はコマンドライン中にあらわれる順番に依存します.

-fno-specialise -O1 を例にとってみましょう. コマンドラインに -fno-specialise があっても,特定化(specialisation)は有効になります. これは -O1-fspecialise を有効にするので,先に指定したフラグを上書きしてしまいます. これとは対照的に -O1 -fno-specialise のようにすると予想どおり特定化は発動しません.

7.3.1. -O*: 便利な最適化フラグの「詰め合わせ」

GHCが生成するコードの質に影響を与えるオプションは 大量に あります. ほとんどの人にとっては,最適化の目標は「素早くコンパイルする」とか「電光石火のごとく走るプログラムコードを生成する」など一般的なものです. したがって,以下にしめすような最適化の「詰め合わせ」を指定(あるいは指定しない)する選択をするだけで十分です.

最適化のレベルを高くすると,モジュールを跨ぐ最適化が増えます. これは,ソースコードを変更したときにどの程度の再コンパイルする必要があるかに大きく影響します. これは開発中は最適化をしないようにすることの理由の1つです.

``-O*``-タイプのオプションを指定することはありません. このオプション意味は,「急いでコンパイルしてね.生成したコードのインスタンスについてはうるさいことは言わないから」です. たとえば ghc -c Foo.hs のようにします.

-O0

「すべての最適化を無効にする」という意味です. -O``オプションを全く指定しないのと同じ状態にするということです. わざわざ ``-O0 を指定するのは make が既に -O オプションを指定してしまっているときに便利です.

-O
-O1

「高品質のコードをそれほど時間をかけないで生成する」という意味です. ghc -c -O Main.lhs のように使います.

-O2

「危険のない最適化をすべて適用する.コンパイルにかなりの時間を書けてもよい」という意味です.

ここで回避しようとしている「危険な」最適化とは,運が悪ければ,実行時における時間・空間性能を 悪化させる 可能性があるということです. 通常これらの最適化は個別に指定します.

-Odph

すべての -O2 の最適化を有効にした上で -fmax-simplifier-iterations=20-fsimplifier-phases=3 を設定します. Data Parallel Haskell (DPH) を使うときように設計されました.

日常の作業で -O* フラグを使うことはありません. それなりの速度が必要なときには -O を使います. たとえば,何かを計測したいときなどです. ちょっと休憩したいときには -O2 を使い(たっぷりのコーヒーブレイクに行き)ます.

-O (など)の「実際の意味」を知りたければ -v を付ければいいでしょう. びっくりして,後ずさりすることになるでしょうね.

7.3.2. -f*: プラットフォーム非依存のフラグ

これらのフラグは個々の最適化を有効/無効にするのに使います. -O を使えば,「デフォルトで有効」となっているフラグをすべて有効にできます. したがって,明示的に指定する必要はないはずです. -fwombat というフラグの否定は -fno-wombat です.

-fcase-merge
Default:有効

直接入れ子になった case 式の検査対象が同じ変数である場合,1つにまとめます. たとえば,

case x of
   Red -> e1
   _   -> case x of
            Blue -> e2
            Green -> e3

は以下のよう変換します.

case x of
   Red -> e1
   Blue -> e2
   Green -> e2
-fcase-folding
Default:有効

あるプリミティブ演算を確認する case 式で定数畳み込みを可能にします. たとえば,

case x `minusWord#` 10## of
   10## -> e1
   20## -> e2
   v    -> e3

は以下のように変換します.

case x of
   20## -> e1
   30## -> e2
   _    -> let v = x `minusWord#` 10## in e3
-fcall-arity
Default:有効

コール・アリティ解析を有効にします.

-fcmm-elim-common-blocks
Default:有効

コード生成器における共通ブロック除去を有効にします. この最適化の目的は,同一の Cmm ブロックを探し,それを除去します.

-fcmm-sink
Default:有効

コード生成器におけるシンキング(コード位置を後ろにずらすこと)のパスを有効にします. この最適化の目的は Cmm の同一のブロックを探すことです. その重複を除去すれば変数束縛を使う場所に近づけられます. このパスではリテラルやレジスタなどの単純な式を埋め込みます.

-fno-cpr-anal

デマンド解析器における CPR 解析を無効にする.

-fcse
Default:有効

共通部分式除去の最適化を有効にします. 共通式としてまとめたくないような unsafePerformIO 式を使っている場合にはこれを無効にするのが便利です.

-fstg-cse
Default:有効

STG 中間言語での共通部分式除去の最適化を有効にします. この段階で表現は同じで型の異なる部分式をまとめられます.

-fdicts-cheap
Default:無効

かなり実験的なフラグで,辞書を値にもつような式のコストを最適化器が安く見積るようにします.

-fdicts-strict
Default:無効

辞書を正格にします.

-fdmd-tx-dict-sel
Default:有効

辞書選択子用に特別な要求変換子を使います.

-fdo-eta-reduction
Default:有効

λ抽象式をη簡約することで,複数のλ抽象式をまとめて除去できるなら,そうします.

-fdo-lambda-eta-expansion
Default:有効

アリティを増やすために let 束縛をη展開します.

-feager-blackholing
Default:無効

通常 GHC はスレッドを切り替える場合にのみサンクをブラックホール化します. このフラグは,サンクに入ってすぐにこれを行うようにします. 以下を参照してください. Haskell on a shared-memory multiprocessor

-fexcess-precision
Default:無効

このオプションを指定すると,中間の浮動小数点数が最終的な型よりも 大きな 精度/範囲をもつことを許すことになります. このことは一般的には良いことです. しかし Float/Double 値がその精度/範囲に正確におさまっていることに依存するプログラムが存在することもあり, そのようなプログラムにはこのオプションを指定してコンパイルしてはいけません.

32-bit x86 のネイティブコード生成器は excess-precision モードしかサポートしておらず -fexcess-precision-fno-excess-precision も効果を持ちません.これは既知のバグです. Bugs in GHC を参照してください.

-fexpose-all-unfoldings
Default:無効

実験的なフラグです.非常に大きな関数や再帰関数も含め,すべての展開を露出します. 通常GHCは大きい関数をインライン化することを避けますが,このフラグによって,全ての関数がインライン化可能になります.

-ffloat-in
Default:有効

let 束縛を内側,利用位置に近づく方向に移動します. Let-floating: moving bindings to give faster programs (ICFP‘96) を参照してください.

この最適化は let 束縛を仕様の位置に近づけます. こうすることの利点は,let の移動先の選択肢が実行されない場合,不要なメモリ領域確保を防ぐことができる点です. また,局所的により多くの情報が得られることになるので,他の最適化パスがより効率よく機能できることになります.

この最適化は常によい方向の効果があるというわけではありません. そういうわけで,GHC はこれを適用するかどうかをある種のヒューリスティクスを使って決定しています. 詳細は複雑ですが,この最適化がよい効果をもたらさない単純な例としては,let 束縛を外側に移動することで, 複数の束縛を1つの大きな束縛にまとめ,メモリ領域の確保を一度に行うことで,ガーベッジコレクタとアロケータが楽になるという場合です.

-ffull-laziness
Default:有効

完全遅延性最適化(let-floating ともいいます)を走らせます. これは let 束縛を計算が少くなるようにと願って,それを囲むλ抽象の外へ移動させることです. これについては Let-floating: moving bindings to give faster programs (ICFP‘96) を参照してください.共有を促進する完全遅延性はメモリの使用量を増加させることになります.

注釈

GHC は完全遅延性を完全には実装していません. 最適化が有効で -fno-full-laziness が指定されていなければ, 共有を促進するある種の変換が実施されます. たとえば,ループの中から繰り返し計算される部分を抽出するといった変換です. この変換は完全遅延の実装で行われるのと同じものですが,GHC は常に完全遅延性を適用するとは限らないので,これに頼ってはいけません.

-ffun-to-thunk
Default:無効

worker-wrapper は使われていない引数を削除しますが,通常はクロージャをサンクにしてしまわないように,全部を削除することはしません. そんなことをしてしまうと,スペースリークしたり,インライン化の妨げになるからです. このフラグは worker/wrapper が すべての λ抽象値を削除できるようにします.

-fignore-asserts
Default:有効

ソースコード中で Exception.assert を使っていても,GHC はこれを無視し(すなわち Exception.assert p ee に書き換え)ます(Assertions を参照してください).

-fignore-interface-pragmas
Default:無効

インターフェイスファイルを読み込むときに不必要な情報はすべて無視するよう GHC に指示します. すなわち M.hi にある関数の展開情報や正格性情報があっても,GHC はこれらの情報を無視します.

-flate-dmd-anal
Default:無効

単純化パイプラインの最後に再度,要求解析(demand analysys)を走らせます. 前段階では見えなかった正格性を発見する場合があり -fspec-constr などの最適化によって作られた関数の未使用引数をこの後段階で取り除けることが判っています. 改善はささやかなものですが,コストもわずかです. Trac wiki page にある注も参照してください.

-fliberate-case
Default:無効だが, -O2 で有効

liberate-case変換を有効にします. これは再帰関数をその右辺で1回展開して,自由変数がくりかえしcaseで検査されるのを回避します. これは,呼び出しパターンの特定(-fspec-constr)に似ていますが -fliberate-case は引数ではなく自由変数を対象にしています.

-fliberate-case-threshold=⟨n⟩
Default:2000

liberate-case変換サイズの閾値を設定します.

-floopification
Default:有効

この最適化を有効にするとコードジェネレータはすべての自己再帰的飽和末尾呼び出しを関数呼び出しではなくローカルジャンプに変換します.

-fmax-inline-alloc-size=⟨n⟩
Default:128

インライン配列の割り当ての最大サイズをnバイトに設定します. GHCは現在の苗床ブロックに静的に判明しているサイズの非固定配列をnバイトで割り当てます. GCの過熱を無視しての割り当てになります.この値はブロックサイズ(通常は4096)よりもかなり小さくする必要があります.

-fmax-inline-memcpy-insns=⟨n⟩
Default:32

展開後の疑似命令が⟨n⟩バイトを超えない場合に memcpy の呼び出しをインライン展開します.

-fmax-inline-memset-insns=⟨n⟩
Default:32

展開後の疑似命令が⟨n⟩バイトを超えない場合に memset の呼び出しをインライン展開します.

-fmax-relevant-binds=⟨n⟩
-fno-max-relevant-bindings
Default:6

型チェッカーは,エラーメッセージに型環境の断片を表示することがありますが, このフラグによって設定される最大数までしか表示されません. -fno-max-relevant-bindings でこれを無効にすると,無制限になります. 構文上のトップレベルの束縛も通常は除外されています(数が多すぎる可能性があるため)が, -fno-max-relevant-bindings を使えばこれらも含められます.

-fmax-uncovered-patterns=⟨n⟩
Default:4

-Wincomplete-patterns および -Wincomplete-uni-patterns で生成される警告に 含めるマッチしないパターンの最大数を設定します.

-fmax-simplifier-iterations=⟨n⟩
Default:4

単純化器の反復回数の最大値を設定します.

-fmax-worker-args=⟨n⟩
Default:10

この数までのワーカーの引数はアンパックされることはありません.

-fno-opt-coercion
Default:無効

強制変換最適化を無効にします.

-fno-pre-inlining
Default:無効

事前インライン展開を無効にします.

-fno-state-hack
Default:無効

State# トークンを引数とするλ抽象式をシングルエントリーであるとみなす “state hack” を無効にします. これにより,その内部のものをインライン化してもよいことになります. そうすると IOモナドおよびSTモナドのコードのパフォーマンスが向上する可能性があります. しかし,共有を減らすリスクがあります.

-fomit-interface-pragmas
Default:無効

GHCに,コンパイルしようとしているモジュール(例えば M)用に生成するインタフェースファイルから すべての本質的ではないな情報を省略するよう指示します. すなわち,M をインポートするモジュールには,M がエクスポートする関数の型だけが見えていますが, 展開や正格性情報などは見えません.したがって,Mがエクスポートする関数は,インポートモジュールでインライン展は開されません. そのメリットは,Mをインポートするモジュールは再コンパイルしなければならない頻度が少なくなるということです. (M のエクスポートで型が変更されたときのみで,実装ののみの変更時は再コンパイルが不要です.)

-fomit-yields
Default:有効

メモリが確保されない場合,GHC がヒープ検査を省略するようにします. これによりバイナリのサイズが 5% ほど改善されますが,メモリ確保のないループを実行している場合, すぐには割り込みがかからないということも意味します. このようなスレッドで常にすぐに割り込みできることが重要な場合は,この最適化を無効にすべきです. 割り込みができることを保証したければ,この最適化を無効にしたうえで, すべてのライブラリを再コンパイルすることを検討してください.

-fpedantic-bottoms

GHC が底値(ボトム,⊥)をより精密に扱うようにします (ただし -fno-state-hack も参照してください). 具体的には,case 式を通しての η 展開が行われなくなります. 通常この η 展開は性能にはよいのですが,部分適用で seq を使っていると悪影響になります.

-fregs-graph
Default:性能を劣化させるバグ(Trac #7679)があるために無効

ネイティブコード生成器との組み合わせでのみ適用します. ネイティブコード生成器において,グラフ彩色レジスタ割り付けをつかいます. デフォルトでは,GHCはもっと単純で速い線形レジスタ割り付けを使います. その欠点は,線形割り付けは通常,よりよくないコードを生成するいことがあるということです.

グラフ彩色割り付けはいくぶんか実験的な実装になっており,レジスタの使い方が厳しいコードでは失敗することがあります. Trac #8657

-fregs-iterative
Default:無効

ネイティブコード生成器との組み合わせでのみ適用します. ネイティブコード生成器において,反復合併グラフ彩色レジスタ割り付けをつかいます. これは -fregs-graph で有効になるレジスタ割り付けと同じですが, レジスタ割り付けのさなかの反復合併(iterative coalescing)が有効になります.

-fsimplifier-phases=⟨n⟩
Default:2

単純化器のフェーズ数を指定の数値に設定します. -O0 を指定すると,この値は無視します.

-fsimpl-tick-factor=⟨n⟩
Default:100

停止しない書き換え規則(Rewrite rules)を書いてしまったり, (もうすこし嫌なことに)データ型を通して再帰するコードを書いてしまったりすると, GHCの最適化器は発散してしまいます(Bugs in GHC). コンパイラが無限ループに陥いるのを避けるため,最適化器は「tickの回数」を保持し, この回数を超過したときには,インライン化と書き換え規則の適用をやめます. 大きいプログラムが多くのtickを使えるように,この限界はプログラムのサイズの定数倍になります. -fsimpl-tick-factor フラッグはこの定数を変更できるようにしたものです. デフォルトの値は 100 で,100より大きな値を指定するとより多くのtick数が使え, 100より小さな値を指定するとより少ないtick数しか使えなくなります.

tick数が尽きると GHC は単純化器をとめ,それまで実行した部分を要約します. -fddump-simpl-stats を使えばより詳細な一覧を生成できます. これにより,ループのほとんどは正確に把握できます.いくつかの数値がかなりの大きさになるからである.

-fspec-constr
Default:無効.-O2 によって有効になる.

呼び出しパターン特定 (Call-pattern specialisation for Haskell programs を参照してください)を有効にします.

この最適化は,引数の「シェイプ」にしたがって再帰関数を特定します. このことは例で説明するのがよいでしょう.以下のような場合を考えましょう.

last :: [a] -> a
last [] = error "last"
last (x : []) = x
last (x : xs) = last xs

このコードでは,リストが空でないとき,帰納部でのパターン照合が冗長であることがわかります. このような場合 -fspec-constr は上のコードを以下のように変換します.

last :: [a] -> a
last []       = error "last"
last (x : xs) = last' x xs
    where
      last' x []       = x
      last' x (y : ys) = last' y ys

不必要なパターン照合を避けるだけでなく,不要な割り当てを回避するのにも役立ちます. これは,引数が自分自身への再帰呼び出しについて正格であっても,最初のエントリについては正格でない場合に適用します. 上記の例のように,関数の正格な再帰的分岐が作成されるのです.

またライブラリの作者が GHC に呼び出しパターンの特定を相当積極的に指示することもできます. 高度に最適化するライブラリでは,特定の数やコードサイズにかかわらず必要になります. 一例として vector ライブラリから単純化した場合を考えてみましょう.

import GHC.Types (SPEC(..))

foldl :: (a -> b -> a) -> a -> Stream b -> a
{-# INLINE foldl #-}
foldl f z (Stream step s _) = foldl_loop SPEC z s
  where
    foldl_loop !sPEC z s = case step s of
                            Yield x s' -> foldl_loop sPEC (f z x) s'
                            Skip       -> foldl_loop sPEC z s'
                            Done       -> z

ここで,ループ本体の引数に SPEC が使われていますので, GHC は foldl 本体を呼び出し側でインライン展開し, foldl_loop で呼び出しパターンの特定を相当積極的に行います. GHC.Types 由来の SPEC はコンパイラが特別に認識します.

(注意: SPEC 引数に対して seq またはバンパターンを使うことが非常に重要です.)

インライン展開した後では,ループ本体から f が直接見えるようになるので, 帰納部に対して激しい特定が可能になります.

-fspec-constr-keen
Default:無効

このフラグが有効であれば,呼び出しパターン特定が,明示的な構成子の引数をもつ, たとえば (f (Just x) に対して行われます.これは関数本体が精査されてなくても行われます. これは時として有益で,たとえば,引数はそれ自体が特定できる他の関数に渡せることもあります.

-fspec-constr-count=⟨n⟩
Default:3

SpecConstr 変換による1つの関数に対する特定の最大数を設定します.

-fspec-constr-threshold=⟨n⟩
Default:2000

SpecConstr 変換用のサイズ閾値を設定します.

-fspecialise
Default:有効

このモジュールで定義された,型クラスによる多重定義関数それぞれをこのモジュールで使われている型について特定します. また,-fcross-module-specialise が有効である場合, INLINABLE プラグマ (INLINABLE pragma) をもつインポートされた関数について, このモジュールで呼ばれている型で特定します.

-fspecialise-aggressively
Default:無効

デフォルトでは,型クラスメソッドおよび INLINABLE あるいは INLINE のマークが付いている関数だけ特定します. このフラグを指定すると,展開可能であればそのサイズにかかわらず多重定義された関数を特定します. コードサイズが著しく大きくなるので,このフラグはどの最適化レベルにも含まれていません. すべての呼び出しを確実に特定したければ -fexpose-all-unfoldings と同時に有効にすることもできます.

-fcross-module-specialise
Default:有効

他のモジュール由来の``INLINABLE`` (INLINABLE pragma)の付いた型クラスにより多重定義された関数を このモジュールで呼ばれる型について特定します. これが効果を発揮するためには,特定が(-fspecialise によって)有効になっていなければなりません.

-fsolve-constant-dicts
Default:有効

制約解決のときに,利用可能な辞書を使てスーパークラスを先行して解決します.

たとえば,

class M a b where m :: a -> b

type C a b = (Num a, M a b)

f :: C Int b => b -> Int -> Int
f _ x = x + 1

の場合 f の本体には Num Int インスタンスが必要です. この制約をコンテキストから解決できるのは C Int bNum Int の解決をもたらすからです. しかし,利用可能な Num Int の辞書を直接解決することで,より良いコードを生成できます. そうすることで,潜在的に多くの関節参照レイヤを除去でき,ディクショナリが静的に識別され, セレクタ関数がインライン展開されるために,その他の最適化に非常によく効きます.

この最適化は辞書を束縛する GADT でも有効です. どのクラスのディクショナリが必要なのか静的に判れば, 実行時に渡されたものを関節的に使用するのではなく,直接解決できます.

-fstatic-argument-transformation
Default:無効

静的引数変換を有効にします.静的引数変換は再帰関数を局所的なループをもつ非再帰関数に変換します. Andre Santos’s PhD thesis の第7章を参照してください.

-fstrictness
Default:有効

正格性解析器を有効にします.GHC の正格性解析器に関するかなり古い論文に Measuring the effectiveness of a simple strictness analyser がありますが,現在の正格性解析器はそれとはかなり違っています.

正格性解析器は,どの引数と変数が関数内で「正格に」使われている(つまり,その関数内でいずれ評価される)かを調べます. これにより,lazyな引数に適用された場合にはプログラムの意味を変えてしまうような最適化(非ボックス化)を GHCが適用できるようになります.

-fstrictness-before=⟨n⟩

単純化器フェーズ ⟨n⟩ の前に正格性解析を追加で走らせます.

-funbox-small-strict-fields
Default:有効

このオプションは,正格であると標示(つまり「!」)された構成子フィールドで, 表現がポインタ一個以下の大きさであるものを可能なら全てアンパックする. これは,大きさの制約を満たす全ての正格なフィールドに UNPACK プラグマ(UNPACK pragma を参照)を付けるのと同じです.

例として,以下のようなデータ型の構成子フィールドを考えましょう.

data A = A !Int
data B = B !A
newtype C = C B
data D = D !C

-funbox-small-strict-fields を有効にすると,これらのフィールドは全て単一の Int# (Unboxed types and primitive operations 参照)の値で表現されます.

このオプションは -funbox-strict-fields に比べると大槌を振り回す感は少なくなります. -funbox-small-strict-fields を使えば,非ボックス化を有効にしている場合, NOUNPACK プラグマ(NOUNPACK pragma 参照)を使って個々の構成子フィールドについてこれを無効にできます.

32ビットプラットフォームでは DoubleWord64Int64 の構成子フィールドは, 技術的にポインタよりも大きいにもかかわらず,アンパックされることに注意してください.

-funbox-strict-fields
Default:無効

このオプションは,正格性を示すマーク(つまり「!」)が付けられた構成子フィールドで, 表現がポインタ一個以下の大きさであるものを可能なら全てアンパックします. これは大きさの制約を満たす全ての正格なフィールドに UNPACK プラグマ(UNPACK pragma 参照)を 付けまわるのと同等です.

このオプションには少々大槌を振り回す感があります. 場合によっては事態を悪化させることもありえます. UNPACK を使ってフィールドを選択的に非ボックス化する方が良いかもしれません. あるいは -funbox-strict-fields を使ってデフォルトで非ボックス化を有効にしつつ, NOUNPACK プラグマ(NOUNPACK pragma 参照)で特定の構成子フィールドをについて 非ボックス化を無効する方が良いかもしれません.

あるいは -funbox-small-strict-fields を使って「小さい」非ボックスフィールドだけにする手もあります.

-funfolding-creation-threshold=⟨n⟩
Default:750

関数の展開候補(unfolding)に許される最大の大きさを定めます. (展開候補には、それが呼び出し点で展開されたときの「コード膨張」のコストを反映した「大きさ」が与えられるます. 大きい関数ほど大きなコストになります.)

その結果として,

  1. これより大きいものは(INLINE プラグマがないかぎり)インライン展開されることはありません.
  2. これより大きいものはインターフェイスファイルにはきだされることはありません.

この値を増やしても,結果として速いコードがえられるというより,単にコンパイル時間が長くなるだけの公算が高いので, -funfolding-use-threshold=⟨n⟩ の方が便利です.

-funfolding-dict-discount=⟨n⟩
Default:30

どの程度,先行してディクショナリのインライン展開を行うか.

-funfolding-fun-discount=⟨n⟩
Default:60

どの程度,先行して関数のインライン展開を行うか.

-funfolding-keeness-factor=⟨n⟩
Default:1.5

どの程度,先行して関数のインライン展開を行うか.

-funfolding-use-threshold=⟨n⟩
Default:60

これはインライン展開にあたっての魔法のカットオフ値です. これより小さい関数定義は呼び出し元に展開され,これより大きい物は展開されません. 関数の大きさは2つのものに依存します. それは式の実際の大きさと,それにコンテキストに依存するインライン展開適用後の式の大きさです.

これと -funfolding-creation-threshold=⟨n⟩ との違いは, こちらは,関数がインライン化されるかどうかを 呼び出し側 で決定するのに対し, あちらは,将来のインライン化のために関数定義を持っておくかどうかを決定することです.

-fvectorisation-avoidance
Default:有効

Data Parallel Haskell (DPH) の一部です.

ベクトル化 回避最適化を有効にします. この最適化は -fvectorise 変換との組み合わせでのみ意味をなします.

DPHを使ったコードのベクトル化は多くの場合非常に効果的ですが, ある種のコードでは酷い結果になることがあります. この最適化は,ベクトル化変換を変更して,関数がベクトル化しないほうが良いかどうかを判断して, 良くなる場合にのみベクトル化を実行するようにします.

-fvectorise
Default:無効

Data Parallel Haskell (DPH) の一部です.

ベクトル化 最適化変換を有効にします. この最適化は DPH を使ったネストしたデータ並列コードを平坦なデータ並列コードに変換します. 平坦なデータ並列コードはよりよい負荷分散が可能で SIMD 並列を可能にし,キャッシュの振舞とも相性がよい.