web-dev-qa-db-ja.com

__asm__ __volatile__( ""::: "memory")の動作

基本的に__asm__ __volatile__ ()は何をし、ARMアーキテクチャ)の"memory"の重要性は何ですか?

42
vnr1992
_asm volatile("" ::: "memory");
_

コンパイラレベルのメモリバリアを作成し、バリアを越えてメモリアクセスを並べ替えないようにオプティマイザを強制します。

たとえば、特定の順序でいくつかのアドレスにアクセスする必要がある場合(おそらく、そのメモリ領域は実際にはメモリではなく別のデバイスによってバッキングされているため)、コンパイラにこれを伝える必要があります。効率化のため。

このシナリオでは、アドレスの値をインクリメントし、何かを読み取って、隣接アドレスの別の値をインクリメントする必要があると想定します。

_int c(int *d, int *e) {
        int r;
        d[0] += 1;
        r = e[0];
        d[1] += 1;
        return r;
}
_

問題は、コンパイラ(この場合はgcc)がメモリアクセスを再配置して、要求するとパフォーマンスを向上できることです(_-O_)。以下のような一連の指示につながる可能性があります。

_00000000 <c>:
   0:   4603        mov r3, r0
   2:   c805        ldmia   r0, {r0, r2}
   4:   3001        adds    r0, #1
   6:   3201        adds    r2, #1
   8:   6018        str r0, [r3, #0]
   a:   6808        ldr r0, [r1, #0]
   c:   605a        str r2, [r3, #4]
   e:   4770        bx  lr
_

_d[0]_と_d[1]_の上記の値は同時にロードされます。これを回避したい場合は、メモリアクセスの順序を変更しないようコンパイラーに指示する必要があります。つまり、asm volatile("" ::: "memory")を使用します。

_int c(int *d, int *e) {
        int r;
        d[0] += 1;
        r = e[0];
        asm volatile("" ::: "memory");
        d[1] += 1;
        return r;
}
_

したがって、命令シーケンスを次のように取得します。

_00000000 <c>:
   0:   6802        ldr r2, [r0, #0]
   2:   4603        mov r3, r0
   4:   3201        adds    r2, #1
   6:   6002        str r2, [r0, #0]
   8:   6808        ldr r0, [r1, #0]
   a:   685a        ldr r2, [r3, #4]
   c:   3201        adds    r2, #1
   e:   605a        str r2, [r3, #4]
  10:   4770        bx  lr
  12:   bf00        nop
_

メモリをフラッシュしたり、ロードまたはストアが完了するのを待つための追加のハードウェアレベルの命令を配置しないため、コンパイラはメモリアクセスの順序を変更することを避けるため、これはコンパイル時のメモリバリアにすぎないことに注意してください。 CPUは、アーキテクチャ機能があり、メモリアドレスが_strongly ordered_またはnormalref )ではなくdeviceタイプである場合、メモリアクセスを並べ替えることができます。

65
auselen

このシーケンスは、Udoが参照している記事に記載されているように、コンパイラメモリアクセスのスケジューリングの障壁です。これはGCC固有のものです-他のコンパイラーはそれらを記述する他の方法があり、それらのいくつかはより明確な(そしてより難解な)ステートメントで記述されています。

__asm__は、アセンブリ言語ステートメントをCコード内にネストして入力できるようにするためのgcc拡張です。ここでは、コンパイラが特定のタイプの最適化を実行できないようにする副作用を指定できるという特性のために使用します不正なコードを生成します)。

__volatile__は、asmステートメント自体が他の揮発性アクセスで再配列されないようにするために必要です(C言語での保証)。

memoryはGCCに対する命令で、インラインasmシーケンスはグローバルメモリに副作用があるため、ローカル変数への影響だけを考慮する必要はありません。

18
unixsmurf

意味は次のとおりです。

http://en.wikipedia.org/wiki/Memory_ordering

基本的には、アセンブリコードが期待どおりに実行されることを意味します。コンパイラーに命令を並べ替えないように指示します。これは、このコードが実行される前にコーディングされ、実行後にコーディングされるものです。

9
Udo Klein