bugfix> performance > 投稿

呼び出されるたびに何らかのアセンブリを挿入するために使用されるnasmマクロを考えてみましょう。この場合、渡された引数が42に等しいかどうかをテストします。

%macro special_handler_if_42 1
    cmp  42, %1
    jne  %%skip
    ; some additional assembly to handle the %1 == 42 case
    push %1
    push 42
    call some_func
%%skip:
%endmacro

場合には 等しい場合、追加のアクションを実行します。それ以外の場合は、マクロに続くコードを続行します。ここまでは順調ですね。

ここで、機能的には同じ方法でマクロを記述します。ただし、非常にまれな「等しい42」の場合は「行外」に移動するため、フォールスルー(ジャンプなし)の場合は次のようなデフォルトのもの(マクロ形式では表示されない):

   cmp  42, rax
    je  equals_42
jump_back:
    ; the rest of the code that follows the macro
    ret
    ; somewhere outside the current function
equals_42:
    push rax
    push 42
    call some_func
    jmp jump_back

これにより、実行時の効率が向上し、iキャッシュ領域を節約できる可能性もあります。そのような非局所的な効果を持つマクロの書き方がわかりません。アイデアを歓迎します。

回答 1 件
  • マクロをテストを実行するマクロとアサーションを処理するマクロの2つのマクロに分割してもかまわない場合は、NASMのコンテキストスタックを使用できます。

    assert_XXX という形式のマクロのシステムを想像しました  これらはすべてかなり似ており、特定のテストを実行します。
    単一の assertions_handler  関数の終わりを過ぎると、必要なハンドラーが生成されます。

    このシステムはコンテキストスタックを使用するため、異なる機能に対して複数回使用できる必要があります。
    基本的に、各 assert_XXX  関数は、スタックと assertions_handler にコンテキストをプッシュします  それらをすべて消費します。

    assert_XXX  コンテキストローカルマクロ argX も定義します  引数をハンドラに渡すため、何もハードコーディングする必要はありません。

    BITS 64
    %macro assert_not_equal 2
        ;Create and push a new context (The name is optional but goodpractice)
        %push assert_equal_ctx
        %define %$arg1 %1
        %define %$arg2 %2
        cmp  %1, %2
        je  %$handler
    %$jump_back:
    %endmacro
    
    %macro assert_greater 2
        %push assert_greater_ctx
        %define %$arg1 %1
        %define %$arg2 %2
        cmp  %1, %2
        jbe  %$handler
    %$jump_back:
    %endmacro
    %macro assertions_handler 0
        %rep 1000
            %ifctx assert_equal_ctx
            %$handler:
                push %$arg1
                push %$arg2
                call somefunc
                jmp %$jump_back
                %pop assert_equal_ctx
            %elifctx assert_greater_ctx
            %$handler:
                push %$arg1
                push %$arg2
                call somefunc2
                %pop assert_greater_ctx
            %else
                %exitrep
            %endif
        %endrep
    %endmacro
    
    ;
    ;TEST TEST TEST TEST TEST TEST TEST TEST
    ; 
    
    assert_not_equal rax, 5
    nop
    nop
    nop
    assert_greater rax, 8
    nop
    nop
    nop
    ret
    assertions_handler
    ;
    ; Handler functions
    ;
    somefunc:
        ret
    somefunc2:
        ret
    
    

    関数ごとのアサーションの最大数は1000に設定されており、最大2まで増やすことができます62

あなたの答え