最適化フラグ-O3があるのに他の最適化フラグ(-O0、-O1、-O2、-Os)と一緒に動作すると、インラインアセンブラルーチンが動作しないのはなぜですか?ARM gccのインラインアセンブラの最適化問題
私はすべてのアセンブラ命令にvolatileを追加しましたが、私はコンパイラに何も触れたり並べ替えないように指示すると思いました。
よろしく
氏Gigu
最適化フラグ-O3があるのに他の最適化フラグ(-O0、-O1、-O2、-Os)と一緒に動作すると、インラインアセンブラルーチンが動作しないのはなぜですか?ARM gccのインラインアセンブラの最適化問題
私はすべてのアセンブラ命令にvolatileを追加しましたが、私はコンパイラに何も触れたり並べ替えないように指示すると思いました。
よろしく
氏Gigu
GCCインラインアセンブラは正しい仕様に非常に敏感です。
特にコンパイラがアセンブラコードを最適化することを決定していないことを確認するには、正しい制約を非常に正確に指定する必要があります。注意すべきことがいくつかあります。例を挙げる。
次の二つ:
int myasmfunc(int arg) /* definitely buggy ... */ { register int myval asm("r2") = arg; asm ("add r1, r0, #22\n" ::: "r1"); asm ("adds r0, r1, r0\n" ::: "r0", "cc"); asm ("subeq r2, #123\n" ::: "r2"); asm ("subne r2, #213\n" ::: "r2"); return myval; }
と
int myasmfunc(int arg) { int myval = arg, plus = arg; asm ("add %0, #22\n\t" : "+r"(plus)); asm ("adds %1, %2\n\t" "subeq %0, #123\n\t" "subne %0, #213\n\t" : "+r"(myval), "+r"(plus) : "r"(arg) : "cc"); return myval; }
は一見同じように見えるかもしれません、あなたは単純に、彼らは同じことを前提としたいです。彼らはそれから非常に遠いです!
このコードの最初のバージョンには複数の問題があります。 1については
asm()
文として、それを指定した場合、コンパイラはイン間任意のコードを挿入に無料です。これは、具体的にはsub
命令を意味しますが、それ自身ではない場合もあります。条件コードを変更すると、コンパイラが挿入するように選択することができます。asm()
ステートメントを指定する際の命令の分割のために、コード生成プログラムがmyval
を両方の時間に入れるために同じレジスタを選択する保証はありませんが、変数宣言のasm("r2")
仕様にもかかわらずです。r0
に関数の引数が含まれているという最初の仮定は間違っています。コンパイラは、アセンブリブロックに到達するまでに、この引数を他の場所に移動することを選択した可能性があります。あなたが分割明細書を再度持ってからさらに悪くなり、何が起こるかについては何も保証されませんとの間に2つのasm()
があります。 __asm__ __volatile__(...);
を指定しても、コンパイラはの2つのブロックを独立したエンティティとして扱います。myval
が壊れている/割り当てていることをコンパイラーに伝えていません。「r2」を壊して帰ってきたときに一時的に他の場所に移動することを選択したかもしれないが、それを...(???)から復元することを決めた。gcc -c tst.c
gcc -O8 -c tst.c
gcc -c -finstrument-functions tst.c
Disassembly of section .text: 00000000 : 0: e52db004 push {fp} ; (str fp, [sp, #-4]!) 4: e28db000 add fp, sp, #0 ; 0x0 8: e24dd00c sub sp, sp, #12 ; 0xc c: e50b0008 str r0, [fp, #-8] 10: e51b2008 ldr r2, [fp, #-8] 14: e2811016 add r1, r1, #22 ; 0x16 18: e0910000 adds r0, r1, r0 1c: 0242207b subeq r2, r2, #123 ; 0x7b 20: 124220d5 subne r2, r2, #213 ; 0xd5 24: e1a03002 mov r3, r2 28: e1a00003 mov r0, r3 2c: e28bd000 add sp, fp, #0 ; 0x0 30: e8bd0800 pop {fp} 34: e12fff1e bx lr Disassembly of section .text: 00000000 : 0: e1a03000 mov r3, r0 4: e2811016 add r1, r1, #22 ; 0x16 8: e0910000 adds r0, r1, r0 c: 0242207b subeq r2, r2, #123 ; 0x7b 10: 124220d5 subne r2, r2, #213 ; 0xd5 14: e1a00003 mov r0, r3 18: e12fff1e bx lr Disassembly of section .text: 00000000 : 0: e92d4830 push {r4, r5, fp, lr} 4: e28db00c add fp, sp, #12 ; 0xc 8: e24dd008 sub sp, sp, #8 ; 0x8 c: e1a0500e mov r5, lr 10: e50b0010 str r0, [fp, #-16] 14: e59f0038 ldr r0, [pc, #56] ; 54 18: e1a01005 mov r1, r5 1c: ebfffffe bl 0 20: e51b2010 ldr r2, [fp, #-16] 24: e2811016 add r1, r1, #22 ; 0x16 28: e0910000 adds r0, r1, r0 2c: 0242207b subeq r2, r2, #123 ; 0x7b 30: 124220d5 subne r2, r2, #213 ; 0xd5 34: e1a04002 mov r4, r2 38: e59f0014 ldr r0, [pc, #20] ; 54 3c: e1a01005 mov r1, r5 40: ebfffffe bl 0 44: e1a03004 mov r3, r4 48: e1a00003 mov r0, r3 4c: e24bd00c sub sp, fp, #12 ; 0xc 50: e8bd8830 pop {r4, r5, fp, pc} 54: 00000000 .word 0x00000000 Disassembly of section .text: 00000000 : 0: e92d4070 push {r4, r5, r6, lr} 4: e1a0100e mov r1, lr 8: e1a05000 mov r5, r0 c: e59f0028 ldr r0, [pc, #40] ; 3c 10: e1a0400e mov r4, lr 14: ebfffffe bl 0 18: e2811016 add r1, r1, #22 ; 0x16 1c: e0910000 adds r0, r1, r0 20: 0242207b subeq r2, r2, #123 ; 0x7b 24: 124220d5 subne r2, r2, #213 ; 0xd5 28: e59f000c ldr r0, [pc, #12] ; 3c 2c: e1a01004 mov r1, r4 30: ebfffffe bl 0 34: e1a00005 mov r0, r5 38: e8bd8070 pop {r4, r5, r6, pc} 3c: 00000000 .word 0x00000000
ご覧のとおり、のいずれも、のいずれも表示されません。コードの2番目のバージョンでは、しかし、gcc -c -O8 ...
上のように終わる:
Disassembly of section .text: 00000000 : 0: e1a03000 mov r3, r0 4: e2833016 add r3, r3, #22 ; 0x16 8: e0933000 adds r3, r3, r0 c: 0240007b subeq r0, r0, #123 ; 0x7b 10: 124000d5 subne r0, r0, #213 ; 0xd5 14: e12fff1e bx lr
、それはあなたがあなたの組み立てと何を期待しているに指定されたものではなく、密接に、です。
Morale:制約とオペランドの割り当てを明示的に正確にして、相互依存関係のある線を内に同じasm()
ブロック内に保持する(複数行の文を作成する)。
これは本当にコメントする必要がありますが、私はいくつかの理由のための1つを投稿することができないんだ:(
コンパイラの最適化あなたと本当に混乱すべきでありませんIgorが言ったように、どのような意味で「機能していませんか?」ASMはコンパイラによって最適化された関数に分岐することがあります。
いくつかのソースファイル以上コンパイラに関する情報が役に立つかもしれません。
初心者はコメントできません。 :-)最初に50ポイントが必要です。私は全く根拠のないupvoteであなたに10を与えます。 'gcc'の –
では、コンパイラの最適化はインラインアセンブリーを非常に重要な方法で混乱させます。これは理解できないほど多くの人に不平を言うが、それは設計/意図によるものであり、変更する可能性は低い。 –
@Bo - ポイントありがとう – NullPointer
「機能しない」と定義します。代わりに何をやろうとしていましたか?ルーチンは何をしていますか?どのように呼びますか?ソースを投稿できますか?生成されたバイナリの逆アセンブリを見ましたか? –
2年後に私の質問に再度訪問した後、私の質問が非常に些細なことでいかに不条理であったかがわかります。それはFrankHが私の質問に答えることをより印象づけます。問題は、レジスタ値を破壊したインラインアセンブラにclobberリストを指定しなかったことです。特定の最適化を行った理由は、おそらく偶然の一致であったと考えられます。 – MrGigu