メインフレームの深淵を覗く:LISTオプションで読み解くPL/I生成コードの「裏側」
若手の諸君、今日もVSAMのレコードと格闘しているか?
「なぜか計算結果が合わない」「なぜかここでS0C7が出る」。そんな時、コンパイラが吐き出す最適化後の機械語を追いかける術を知っているか? マニュアルの字面を追うのも大切だが、真のメインフレーマーは、コンパイラがソースコードをどう解釈し、最終的にどのレジスタを使って演算しているのかを理解している。
今日は、PL/Iのコンパイルオプション `LIST` を使って、生成されたアセンブラ相当のコードを読み解き、プログラムの「挙動」を物理的に追いかける技術を伝授しよう。
—
1. なぜ「LIST」オプションが必要なのか
PL/Iは高級言語だ。`A = B + C;` と書けば、コンパイラはそれを適切なアセンブラ命令に変換する。だが、`FIXED BIN` の精度や `FLOAT` の丸め誤差、あるいは複雑な `ON` ユニットの制御フローにおいて、コンパイラが我々の意図をどう機械に変換したのかを確認しなければならない局面が必ず来る。
`LIST` オプションを付与すると、コンパイルリストの末尾に、ソース行に対応した機械語命令列が生成される。これを見ることで、「この一行が、実はこれだけのCPUサイクルを消費しているのか」という事実が手に取るようにわかるはずだ。
—
2. 実践:VSAM読み込みと演算のコードを紐解く
まずは、現場でよくある「VSAMから読み込み、特定条件で加算して出力する」というシンプルなプロセスのコードを見てくれ。
/i
TESTPROG: PACKAGE OPTIONS(MAIN);
/ VSAM定義: 顧客マスターファイル /
DCL MSTR_FILE FILE RECORD INPUT ENV(VSAM KEYED);
DCL 1 MSTR_REC,
3 CUST_ID CHAR(5),
3 BALANCE FIXED DEC(9,2);
/ 処理用変数 /
DCL TOTAL_BAL FIXED DEC(11,2) INIT(0);
/ ファイルオープンとレコード処理 /
OPEN FILE(MSTR_FILE);
ON ENDFILE(MSTR_FILE) BEGIN;
PUT SKIP LIST(‘処理完了: 総額 = ‘ || TOTAL_BAL);
CLOSE FILE(MSTR_FILE);
STOP;
END;
DO FOREVER;
READ FILE(MSTR_FILE) INTO(MSTR_REC);
/ ここでの演算がどう機械語になるかがLISTの醍醐味 /
TOTAL_BAL = TOTAL_BAL + MSTR_REC.BALANCE;
END;
END TESTPROG;
—
3. LIST出力から何を読むべきか(解析のポイント)
このコードをコンパイルする際、`LIST` を指定すると、出力リストに以下のようなセクションが現れる(実際のアウトプットは環境により異なるが、本質は変わらない)。
18 TOTAL_BAL = TOTAL_BAL + MSTR_REC.BALANCE;
0001A0 5850 D010 L 5,16(0,13)
0001A4 F822 5000 5000 ZAP 5(3,5),0(3,5) <-- 内部的な演算フロー
ここで注目すべきは以下の3点だ。
① データのロード位置
`L`(Load)命令がどのベースレジスタを使っているかを見れば、変数 `TOTAL_BAL` がどこに確保されているか(静的領域か、スタックか)が一目瞭然だ。もし期待しないアドレスを参照していれば、データ定義(DCL)のミスが即座に判明する。
② 演算命令の正体
`FIXED DEC` は、内部的には `PACKED-DECIMAL` 演算(`AP`命令や`ZAP`命令)に変換される。もしこれが `FIXED BIN` であれば、`A`(Add)命令が生成される。この変換過程を見ることで、パフォーマンスチューニングのヒントを得ることができる。例えば、ループ内で不要な型変換が起きていないか、コンパイラの「親切心」が逆に重荷になっていないかを判断する材料になる。
③ ONユニットの飛び先
`ON` ユニットが記述されている場合、コンパイラは内部的に「トラップ」を仕掛けている。`LIST` を見れば、`ENDFILE` が発生した際に、どのラベルへ `Branch` して `ON` ユニットのブロックへ遷移するのか、その制御フローの「線」が見えてくる。
—
4. エンジニアへのアドバイス:デバッグの極意
諸君、もし大規模改修で「なぜか値が化ける」というバグに遭遇したら、まずは `LIST` を出す。そして、ソースコードの行番号と、アセンブラ命令が対応している箇所を指でなぞるんだ。
- 「この変数は本当にこのレジスタに入っているのか?」
- 「この命令の後のレジスタの値は、想定通りか?」
これを繰り返すと、単なるツールとしてのコンパイラではなく、IBMのシステムアーキテクトがどのようにメモリを管理しようとしているのかが見えてくる。これは、どんな高レベルな言語を扱うにしても変わらない、エンジニアの「勘」を養うための最高のトレーニングだ。
PL/Iは古い言語だと言われることもある。だが、この「ハードウェアと直結した透明性」こそが、基幹系バッチ処理において最強の武器になる。コードの裏側を覗く勇気を持つこと。それが、トラブルを恐れない強固なシステムを作る第一歩だ。
何か詰まったら、いつでも聞け。我々の戦場(メインフレーム)は、理論と実装の積み重ねの上に成り立っているのだから。
