Forth エンジンなどのスタック・マシン・エミュレータの重要な最適化は、 1 つ以上の最上位側スタック項目をレジスターに保持することです。
ワードにスタック効果 ( in1...inx -- out1...outy )
がある場合、 上位の
n 項目をレジスターに保持します:
特に、 レジスターの数が十分であれば、 1 つの項目をレジスターに保持しておくことは決して不利にはなりません。 ?branch
や定数や変数やリテラルや i
などの頻繁に使用されるワードにとって、 2 つの項目をレジスターに保持することは不利になります。
したがって、 ジェネレーターは、 レジスターに 0 個または 1 つの項目を保持するコードのみを生成します。 生成された
C言語のコードは両方のケースをカバーします。 これらの選択肢の選択は、 C言語のコンパイル時にスイッチ -DUSE_TOS
を使用して行われます。 +
の C言語コードの TOS
は、 1 項目の場合は単なる変数名ですが、 それ以外の場合は
sp[0]
に展開されるマクロです。 注意: GNU C コンパイラーは TOS
のような単純な変数をレジスターに保持しようと試み、 十分な数のレジスターがあれば、 それは通常は成功することに注意してください。
プリミティブ・ジェネレーターは、 浮動小数点数スタックの TOS 最適化も実行します(-DUSE_FTOS
)。 浮動小数点数演算の場合、
この最適化の利点はさらに大きくなります。 浮動小数点数演算は、 ほとんどのプロセッサで非常に時間がかかりますが、
その結果が利用されない間は他の演算と並行して実行できます。 FP-TOS がレジスターに保持されている場合、 他の演算との並行しての実行が機能します。
スタック上、 つまりメモリー内に保持されている場合、 メモリーへのストアは浮動小数点数演算の結果を待つ必要があり、
プリミティブの実行時間が大幅に長くなります。
TOS の最適化により、 プリミティブの自動生成がちょっぴり複雑になります。 sp[0]
のすべての出現を TOS
に置き換えるだけでは十分ではありません。 考慮すべき特殊なケースがいくつかあります:
dup ( w -- w w )
で、 TOS 最適化がオンになっている場合、
ジェネレーターはスタック上の項目の元の場所へのストアを削除してはなりません。
(-- out1...outy)
の形式のスタック効果を持つプリミティブは、 開始時に TOS
をスタックに保存する必要があります。 同様に、 スタック効果 in1...inx --)
を持つプリミティブは、
最後にスタックから TOS をロードする必要があります。 ただし、 null スタック効果 --
の場合、
ストアやロードは生成されません。