私は、非常に単純なスタックベースの言語用の小さなコンパイラ (llvm を使用していますが、問題ではありません) に取り組んできました。
私は、評価スタックベースの言語を TAC または SSA に翻訳することに関する多くの論文を読んできました。一般的に概説されている基本的な手順は、コードを基本ブロックに分割し、すべての命令でスタックの高さを分析し、その割り当てを使用することです。高さを名前として使用して、スタック内の各位置を登録します。次に、基本ブロックの正味のプッシュとポップを分析し、必要に応じてそれらの間でレジストリを転送します。
ただし、この情報では、理解できない単純なケースがあります。たとえば、次の擬似コード:
1: ...
2: READ
3: IF 0 GO TO 4 ELSE GOTO 2
4: ...
READ がどこかから値を取得してスタックにプッシュする関数であると仮定すると、この関数は READ 命令を使用して単純な基本ブロックを作成し、おそらく最後に減算と分岐を行います (if が値をポップしないと仮定します)スタック)。
問題は、スタックの使用状況を分析しただけではポップがなく、プッシュが 1 つしかないため、渡す必要がある値が 1 つしかないことです。ただし、ループが進行すると、ストレージ用のレジストリが 1 つしかないため、すべての読み取りが失われます。
この事件に関するテキストは見つかりませんでした。変換されたプログラムと一緒に実際のスタックを保持することになっていますか? この場合、すべての基本ブロック間の関係に依存するため、実際のスタックから値をプッシュまたはポップアウトする必要がある時期を見つけることは簡単ではないようです。
これについて読む記事や論文はありますか?どんな助けでも大歓迎です、ありがとう。