0

このコードをコンパイルすると

void FastRead()
{
    register uint32_t cnt = 1000, sample;
    register uint8_t *dst = data;
    asm volatile(
    "loop1:"
        "ldr     %[sample], [%[src]]\n\t"
        "strb    %[sample], [%[dst], #1]!\n\t"
        "subs    %[cnt],1 \n\t"                
        "bne     loop1\n\t"
        : [cnt] "+r" (cnt), [dst] "+r" (dst), [sample] "=r" (sample)
        : [src] "r" (&CORE_PIN16_PINREG)
    );
}

レジスタ割り当ては、「コンパイル」後にこのコードを生成します

000004dc <_Z8FastReadv>:
     4dc:   f44f 737a   mov.w   r3, #1000   ; 0x3e8
     4e0:   4a03        ldr r2, [pc, #12]   ; (4f0 <loop1+0xc>)
     4e2:   4904        ldr r1, [pc, #16]   ; (4f4 <loop1+0x10>)

000004e4 <loop1>:
     4e4:   6809        ldr r1, [r1, #0]  ;         <--  ?!?!?!?!?!?
     4e6:   f802 1f01   strb.w  r1, [r2, #1]!
     4ea:   3b01        subs    r3, #1
     4ec:   d1fa        bne.n   4e4 <loop1>
     4ee:   4770        bx  lr
     4f0:   1fff8820    .word   0x1fff8820
     4f4:   400ff050    .word   0x400ff050

src を読み取り専用レジスタに指定しましたが、「コンパイラ」がそれを上書きできるという意味ではありませんね。簡単な回避策は、すべての変数を読み取り/書き込み可能 (+r) にすることです。

しかし、何が原因なのですか、これはバグですか、それともなぜこれが起こっているのか説明してもらえますか?

編集:言及するのを忘れて申し訳ありませんが、これは gcc コンパイラを使用する Linux での私たちです (arm-none-eabi-g++ バージョン 4.7.2 と 4.8.4 の両方)

4

1 に答える 1

1

これはコンパイラのバグではありません。asm 操作の入力/出力に対するコンパイラのモデルは、次のように実行されます。

  1. 入力を読み取る
  2. 操作を行う
  3. 書き込み出力

したがって、コンパイラは任意の出力値を入力値と同じレジスタに割り当てることができます。

例のように asm ステートメントに一連の命令がある場合、一部の入力が読み取られる前に一部の出力が書き込まれます。答えは、 https: //gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Extended-Asm のインライン asm 制約に関するドキュメントにあります。

この問題を解決するために必要な部分は次のとおりです。

「&」を使用します 入力とオーバーラップしてはならないすべての出力オペランドに対する制約修飾子 (修飾子を参照)。それ以外の場合、GCC は、アセンブラー コードが出力を生成する前にその入力を消費すると仮定して、無関係な入力オペランドと同じレジスターに出力オペランドを割り当てる可能性があります。アセンブラ コードが実際に複数の命令で構成されている場合、この仮定は誤りである可能性があります。

出力制約を次のように変更した場合:

: [cnt] "+&r" (cnt), [dst] "+&r" (dst), [sample] "=&r" (sample)

その後、問題を修正します。

于 2015-03-25T01:38:00.837 に答える