日本-日本語
日本HPホーム 製品 & サービス OpenVMS製品情報
≫  お問い合わせ


OpenVMS マニュアル


 

OpenVMS ドキュメント
ライブラリ

タイトルページ
目次
まえがき
第 1 部 : 概念と方法
第 1 章:Macro-32コードの移植の準備
第 2 章:MACROコンパイラのプラットフォームごとの動作
第 3 章:ソースに対する推奨される変更と必要な変更
第 4 章:移植したコードの性能改善
第 5 章:MACROの64ビット・アドレッシングのサポート
第 2 部:リファレンス・セクション
付録 A :MACROコンパイラの修飾子
付録 B :専用の指示文
付録 C :MACROコンパイラ・ビルトイン
付録 D :VAXからAlphaまたはI64への移植用のマクロ
付録 E :64ビット・アドレッシング用のマクロ
索引
PDF
OpenVMS ホーム
HP OpenVMS MACRO コンパイラポーティングおよびユーザーズ・ガイド

HP OpenVMS MACRO コンパイラ
ポーティングおよびユーザーズ・ガイド


目次 索引



MOVPSL 命令は, OpenVMS Alpha の PS をフェッチします。この内容は, VAX の PSL (プロセッサ・ステータス・ロングワード) と異なります。たとえば, OpenVMS Alpha と OpenVMS I64 の PS には条件コード・ビットが含まれていません。 OpenVMS Alpha の PS についての詳細は, Alpha Architecture Reference Manual を参照してください。

推奨される変更

MOVSPL 命令はめったに使用されません。コードに MOVPSL 命令が含まれている場合, OpenVMS Alpha システムまたは OpenVMS I64 システムに移植するためには,コードを書き換える必要があります。

3.2.10 マクロによって実装される命令

VAX Macro-32 の一部のオペレーション・コードは, Alpha Macro-32 ではビルトインになり (機能を実行するために PAL またはルーチン呼び出しにコンパイルされることがあります), Itanium ではマクロとなります (これもルーチン呼び出しに展開されることがあります)。

マクロとなったこれらのオペレーション・コードは,命令とマクロの構文上の細かい違いが原因でエラーとなることがあります。通常,オペレーション・コードのパラメータは,引数内に式がある可能性があるため,コンマで区切る必要があります。マクロの引数は単純にテキストであるため,コンマだけでなくスペースやタブも引数のセパレータと見なされます。 (一部のマクロ引数は式のように見えますが,評価されるコンテキストでのマクロ展開で使用されるまでは, Macro-32 で式としては扱われません。)

不要なスペースがなくなるように再フォーマットすることで,ソース・コードを修正することができます。

次の VAX MACRO ファイルはこの違いを示します。

.macro Prober_mac a,b,c 
    prober  a,b,c 
.endm 
 
    prober one, two-too(r2), three(r3)          ; This one works. 
 
    Prober_mac one, two-too(r2), three(r3)      ; This one works. 
 
    prober one, two - too(r2), three(r3)        ; This one works. 
 
    Prober_mac one, two - too(r2), three(r3)    ; This one fails 
                                                ; because the spaces are 
                                                ; argument separators. 
 
    prober       one, -            ; This one works. 
                 two - -           ; Note the second argument is 
                 too(r2), -        ; separated onto two lines. 
                 three(r3) 
 
    Prober_mac -                   ; This one fails. 
                 one, - 
                 two - -           ; Note the second argument is 
                 too(r2), -        ; separated onto two lines. 
                 three(r3) 
 
    Prober_mac -                   ; This one works because there 
                 one, -            ; are no spaces or tabs before 
                 two--             ; or after the continuation 
too(r2), -                         ; line break. 
                 three(r3) 
 
    Prober_mac -                   ; This one works, too. 
                 r1, - 
                 r2, - 
                 r3 
 
.end 



3.3 フロー制御メカニズム

VAX MACRO で使用される一部のフロー制御メカニズムは, OpenVMS Alpha システムや OpenVMS I64 システムでは,望ましい結果になりません。そのため,若干のコード変更が推奨または必要となります。

制御のフローを変更するために, JSB ルーチン内でスタック上の戻りアドレスを変更するコードがこのカテゴリに含まれます。これにはいくつかのバリエーションがあり,よく使用されます。すべて再コーディングが必要です。

3.3.1 条件コードによる通信

JSB 命令の直後に条件分岐があったり,ルーチンの最初の命令が条件分岐になっていると,コンパイラはこれを検出してエラー・メッセージを出力します。

推奨される変更

条件コードによる暗黙的な通信を行う代わりに,状態値またはフラグ・パラメータを返します。

例を示します。

BSBW    GET_CHAR 
BNEQ    ERROR           ; Or BEQL, or BLSS or BGTR, etc 

これを,次のように書き替えます。

BSBW    GET_CHAR 
BLBC    R0, ERROR       ; Or BLBS 

すでに R0 を使用している場合は,スタックにプッシュし,エラーを処理し終えてから復元する必要があります。

3.3.2 JSB ルーチンから CALL ルーチン内への分岐

JSB ルーチンから CALL ルーチン内への分岐があり, .JSB_ENTRY ルーチンがレジスタを保存する場合,情報レベル・メッセージが出力されます。このような分岐に対してメッセージが出力される理由は,保存されているレジスタを復元するための,プロシージャのエピローグ・コードが実行されないためです。レジスタを復元する必要がない場合は,変更は不要です。

推奨される変更

.JSB_ENTRY ルーチンは,おそらく呼び出し元に代わって RET を実行しようとしていると考えられます。 JSB_ENTRY によって保存されたレジスタを, RET を実行する前に復元する必要がある場合は, .CALL_ENTRY 内の共通コードを .JSB_ENTRY に変更し,両方のルーチンから呼び出すようにします。

たとえば,次のコード例があるとします。

Rout1:  .CALL_ENTRY 
        . 
        . 
X:      . 
        . 
        . 
        RET 
Rout2:  .JSB_ENTRY INPUT=<R1,R2>, OUTPUT=<R4>, PRESERVE=<R3> 
        . 
        . 
        BRW X 
        . 
        . 
        RSB 

このコードを OpenVMS Alpha システムまたは OpenVMS I64 システムに移植するには,次のように .CALL_ENTRY ルーチンを 2 つのルーチンに分割します。

Rout1:  .CALL_ENTRY 
        . 
        . 
        JSB X 
        RET 
X:      .JSB_ENTRY INPUT=<R1,R2>, OUTPUT=<R4>, PRESERVE=<R3> 
        . 
        . 
        RSB 
Rout2:  .JSB_ENTRY INPUT=<r1,r2>, OUTPUT=<R4>, PRESERVE=<R3> 
        . 
        . 
        JSB X 
        RET 
        . 
        . 
        RSB 



3.3.3 スタックへの戻りアドレスのプッシュ

コンパイラは,たとえば (PUSHAB label) のように,アドレスをスタックにプッシュし,以降の RSB でその場所から実行を再開しようとする操作をすべて検出し,エラーとして出力します。 ( OpenVMS VAX システムでは,次の RSB でルーチンの呼び出し元に戻ります。)

推奨される変更

アドレスの PUSH を削除し,現在のルーチンの RSB の直前に分岐先ラベルへの明示的な JSB を追加します。これで同じ制御フローとなります。分岐先ラベルは .JSB_ENTRY ポイントとして宣言します。

たとえば,次のコードではソース・コードの変更が必要としてメッセージが出力されます。

Rout:   .JSB_ENTRY 
        . 
        . 
        PUSHAB  continue_label
        . 
        . 
        RSB 

明示的な JSB 命令を追加することで,次のようにコードを変更します。 JSB を RSB の直前に配置している点に注意してください。この前のコードでは, PUSHAB がどこにあっても, continue_label に制御を渡すのは RSB 命令でした。新しいコードでは PUSHAB が削除されています。

Rout:   .JSB_ENTRY 
        . 
        . 
        . 
        JSB     continue_label
        RSB 



3.3.4 スタック上の戻りアドレスの削除

コンパイラは,スタック上の戻りアドレスの削除 (たとえば TSTL#(SP)+) を検出して,エラーとして出力します。 VAX コードでは,戻りアドレスを削除することで,呼び出し元のさらに呼び出し元に戻ることができます。

推奨される変更

呼び出し元に対して,その呼び出し元に戻る必要があることを示す状態値を返すように,ルーチンを書き換えてください。また,最初の呼び出し元から継続ルーチンのアドレスを渡し,最下位のルーチンがそこに JSB で分岐する方法もあります。継続ルーチンが RSB で最下位のルーチンに戻ったら,最下位のルーチンが RSB で戻ります。

たとえば,次のコードに対しては,ソースの変更が必要であるというメッセージがコンパイラから出力されます。

Rout1:  .JSB_ENTRY 
        . 
        . 
        JSB   Rout2 
        . 
        RSB 
Rout2:  .JSB_ENTRY 
        . 
        . 
        JSB   Rout3       ; May return directly to Rout1 
        . 
        RSB 
Rout3:  .JSB_ENTRY 
        . 
        . 
        TSTL  (SP)+       ; Discard return address 
        RSB               ; Return to caller's caller 

次のように,状態値を返すようにコードを書き換えることができます。

Rout2:  .JSB_ENTRY 
        . 
        . 
        JSB          Rout3 
        BLBS R0, No_ret   ; Check Rout3 status return 
        RSB               ; Return immediately if 0 
No_ret: . 
        . 
        RSB 
Rout3:  .JSB_ENTRY 
        . 
        . 
        CLRL  R0          ; Specify immediate return from caller 
        RSB               ; Return to caller's caller 



3.3.5 戻りアドレスの変更

コンパイラは,スタック上の戻りアドレスを変更する操作をすべて検出し,エラーとして出力します。

推奨される変更

スタック上の戻りアドレスを変更するコードは,呼び出し元に状態値を返すように書き換えてください。状態値を受け取った呼び出し元が特定の場所に分岐したり,状態値として特別な .JSB_ENTRY ルーチンのアドレスを返して,呼び出し元からそのルーチンを呼び出すようにすることができます。後者の場合,呼び出し元は,特別な .JSB_ENTRY ルーチンに対して JSB を実行した直後に, RSB を実行する必要があります。

たとえば,次のコードに対して,コンパイラはソースの変更が必要である旨出力します。

Rout1:  .JSB_ENTRY 
        . 
        . 
        JSB  Rout2                    ; Might not return 
        . 
        RSB 
Rout2:  .JSB_ENTRY 
        . 
        . 
        MOVAB continue_label, (SP)   ; Change return address 
        . 
        RSB 

次のように,戻り値を返すようにコードを書き換えます。

Rout1:  .JSB_ENTRY 
        . 
        . 
        JSB   Rout2 
        TSTL  R0                      ; Check for alternate return 
        BEQL  No_ret                  ; Continue normally if 0 
        JSB   (R0)                    ; Call specified routine 
        RSB                           ; and return 
No_ret: . 
        . 
        RSB 
Rout2:  .JSB_ENTRY 
        CLRL  R0 
        . 
        . 
        MOVAB  continue_label, R0    ; Specify alternate return 
        RSB 



3.3.6 コルーチン呼び出し

2 つのルーチン間でのコルーチン呼び出しは,一般にそれぞれのルーチン内で一連の JSB 命令として実装されます。それぞれの JSB は,スタック上の戻りアドレスに制御を渡し,その過程でその戻りアドレスを削除します (たとえば,JSB @(SP)+)。コンパイラはコルーチン呼び出しを検出し,エラーとして出力します。

推奨される変更

コルーチン・リンケージを開始するルーチンを,明示的なコールバック・ルーチン・アドレスを他のルーチンに渡すように書き換える必要があります。その後,コルーチンを開始するルーチンは, JSB 命令で他のルーチンを呼び出します。

例として,次のコルーチン・リンケージを考えます。

Rout1:  .JSB_ENTRY 
        . 
        JSB Rout2   ; Rout2 will call back as a coroutine 
        . 
        JSB @(SP)+  ; Coroutine back to Rout2 
        . 
        RSB 
Rout2:  .JSB_ENTRY 
        . 
        JSB @(SP)+  ; coroutine back to Rout1 
        . 
        RSB 

このようなコルーチン・リンケージに参加しているルーチンを,次のように,明示的なコールバック・ルーチン・アドレス (ここでは R6 と R7 内) を交換するように変更します。

Rout1:  .JSB_ENTRY 
        . 
        . 
        MOVAB Rout1_callback, R6 
        JSB Rout2 
        RSB 
Rout1_callback: .JSB_ENTRY 
        . 
        . 
        JSB  (R7)    ; Callback to Rout2 
        . 
        RSB 
Rout2:  .JSB_ENTRY 
        . 
        . 
        MOVAB Rout2_callback, R7 
        JSB (R6)    ; Callback to Rout1 
        RSB 
Rout2_callback: .JSB_ENTRY 
        . 
        RSB 

レジスタの消費を避けるには,ルーチンの入口でコールバック・ルーチンのアドレスをスタックにプッシュします。次に,JSB @(SP)+ 命令を使用して, "直接"コールバック・ルーチンに JSB で分岐します。次の例では,コールバック・ルーチンのアドレスを R0 で渡していますが,ルーチンの入口ですぐにプッシュしています。

Rout1:  .JSB_ENTRY 
        . 
        . 
        MOVAB Rout1_callback, R0 
        JSB rout2 
        RSB 
Rout1_callback: .JSB_ENTRY 
        PUSHL   R0      ; Push callback address received in R0 
        . 
        . 
        JSB     @(SP)+  ; Callback to rout2 
        . 
        . 
        RSB 
Rout2:  .JSB_ENTRY 
        PUSHL   R0      ; Push callback address received in R0 
        . 
        . 
        MOVAB Rout2_callback, R0 
        JSB @(SP)+      ; Callback to Rout1 
        RSB 
Rout2_callback: .JSB_ENTRY 
        . 
        . 
        RSB 



3.3.7 REI を使用したモードの変更

VAX での REI 命令の一般的な用途は,明示的な移行先 PC と PSL をスタックにプッシュすることで,モードを変更することです。以下の理由から,このコードは,ソース・コードをいくらか変更しないと, OpenVMS Alpha システムや OpenVMS I64 システムではコンパイルできません。

  • OpenVMS Alpha のデスティネーション・コードでは,リンケージ・セクション・ポインタが確立されている必要があります。 OpenVMS I64 のデスティネーション・コードでは, GP が確立されている必要があります。 REI では,そのための方法が提供されていません。

  • Integrity サーバの REI フレームは, Alpha システムや VAX システムよりも複雑で,保存された汎用レジスタ,その他のレジスタ,レジスタ・スタックについての情報が含まれています。同様に,Alpha システムの REI フレームは VAX システムよりも複雑で,保存されたレジスタが含まれています。
    Itanium でのプロローグ・コードでは,レジスタ・フレームを確立する必要があります。
    また, Itanium および Alpha では,すべてのサブルーチンには,保存された非スクラッチ・レジスタを復元するためのエピローグ・コードがあります。レジスタの受け渡しと復元を可能にするためには,新しい構文が必要です。

  • モード変更は,移行先にある別のスタック上でプロセスを実行することを意味します。そのため,以前のスタックをクリアしなくてはならにという新しい要件が発生します。

推奨される変更

OpenVMS Alpha システムや OpenVMS I64 システムで同等の機能を実行するために,システム・ルーチン EXE$REI_INIT_STACK が作成されました。このルーチンは,新しいモードとコールバック・ルーチンのアドレスをパラメータとして受け取ります。このルーチンには,高級言語からも使用できるという利点があります。

このルーチン呼び出しを使用できるように,既存のコードを再構成する必要があります。実行を継続するコード・ラベルは,システム・ルーチンから呼び出されるため,エントリ・ポイント指示文で宣言する必要があります。

次の例は, VAX MACRO コードで RET 命令を使用してモードを変更する 2 つの方法と, OpenVMS Alpha または OpenVMS I64 において,同じことを EXE$REI_INIT_STACK ルーチンを使用して実現する 1 つの方法を示します。

変更前 (1)

PUSHL  new_PSL
PUSHL new_PC
REI 

変更前 (2)

PUSHL     new_PSL
JSB       10$ 
 . 
 . 
 . 
CONTINUE                   ;With new PSL
 . 
 . 
 . 
10$:  REI 

変更後

PUSHL     Continuation_routine
PUSHL     new_mode         ;Not a PSL 
CALLS #2, exe$rei_init_stack 
 . 
 . 
 . 
Continuation_routine:  .JSB_ENTRY 

プログラムが継続ルーチンに到達すると,新しいモードで新しい場所から実行され,古いモードのスタックは再初期化されます。メモリ・スタックと ( OpenVMS I64 の場合) レジスタ・スタックのベースは,新しいモードのものに設定されます。

外部モードのルーチンに引数を渡すという問題がある点に注意してください。 OpenVMS Alpha システムでは,ほとんどのレジスタは REI にまたがって保持されます。 OpenVMS I64 システムでは, R26,R27,および R10 (Alpha レジスタ R8,R9,R10 に相当) だけが保持されます。より多くのデータを渡す必要がある場合,内部モード・スタックにデータ構造を作成し,レジスタを通じてそのアドレスを外部モード・ルーチンに渡すことはできません。内部モード・スタックは, EXE$REI_INIT_STACK によってベースにリセットされるためです。代わりに,MFPR_xSP および MTPR_xSP を使用して外部モード・スタックに領域を割り当て,そこにデータを格納する必要があります。

3.3.8 ループのネスト制限

コンパイラは,正しくコードを生成するために,プログラム・コード中のループを検出する必要があります。ループの中に別のループがあったり,部分的に別のループと重なると, "ネストした"ループとなります。ループのネストが 32 レベルを超えると,コンパイラは回復不可能なエラーが発生したことを報告し,コンパイルが停止します。 VAX MACRO アセンブラではループを検出する必要がないため,このような制限はありませんでした。

推奨される変更

コンパイラによってこのエラーが報告された場合は,この制限を超えないようにコードを再構成してください。


目次 索引

© 2012 Hewlett-Packard Development Company, L.P.