2012-06-03 29 views
9

これは簡単な質問ではありません。
注:純粋なasmを使用するための意見やアドバイスは必要ありません。私は実際に私が話していることをやり遂げる必要があります:この記号なしでインラインasmを得るには/ゼロは短いintに結果を割り当てるときにオプコードを拡張します。

私は多くの機能のために16ビットの短絡を悪用するライブラリを扱っており、私はそれを最適化しています。インラインasmでいくつかの最適化された関数を追加する必要があります。問題は、多くの場所で、関数の結果が短いintに割り当てられていることです。つまり、コンパイラはuxまたはsx番目のアームオペコードを生成します。

私の目標は、この問題を回避し、この無駄なオペコードが生成されないようにすることです。 まず、intを返すように私の最適化された関数を定義する必要があります。このようにintまたはshort intに代入された場合、結果を変換するための余分なオペコードはありません。

問題は、自分の関数内でコンパイラが生成するint - > short変換をスキップする方法がないということです。
ダムキャスト:*(short*)(void*)&valueは機能しません。コンパイラは、スタックを問題にして混乱を招きかねません。あるいは、同じsxthを使用して結果を符号拡張します。

私は複数のコンパイラでコンパイルしましたが、アームのarmccコンパイラで解決できましたが、GCCでコンパイルできません(4.4.3または4.6.3でコンパイルできます)。 armccでは、短いタイプのインラインasm文を使用します。短いコンパイラを使用していても何らかの理由でgccで拡張子が必要だと考えています。

C/C++ intをshortとinlineに変換するasm(ARM固有)

私はGCCで作業することができない簡単なコードスニペットがあります。どのように動作するのかアドバイスはありますか?この単純な例のために私は、CLZ命令を使用します:

サンプルファイルtest.cのファイル:



static __inline short CLZ(int n) 
{ 
    short ret; 
#ifdef __GNUC__ 
    __asm__("clz %0, %1" : "=r"(ret) : "r"(n)); 
#else 
    __asm { clz ret, n; } 
#endif 
    return ret; 
} 

//test function 
short test_clz(int n) 
{ 
    return CLZ(n); 
} 



は、ここで私は-O3 -cのarmccで得た結果予想です

test_clz: 
    CLZ  r0,r0 
    BX  lr 

ここでGCC -c -O3が私を与えることを容認できない結果だ:

は、
test_clz: 
    clz r0, r0 
    sxth r0, r0 
    bx lr 

short ret;ではなく、内部変数int ret;でCLZを書き換えると、armccはGCCと同じ結果を生成することにも注意してください。

GCCまたはのarmccでのasm出力を得るためにクイックライン:
gcc -O3 -c test.c -o test.o && objdump -d test.o > test.s
armcc -O3 --arm --asm -c test.c

+1

インラインアセンブリをスキップして、最適化されたビットをアセンブリで記述された関数全体として書くのはなぜですか?あなたの問題は、C関数とインラインasmの混在から来ているようです。しかし、なぜ内部にたくさんのasmが入っているC関数を書くのですか? – TJD

+0

はオプションではありません。私は本当に完全にasmで書かれている必要がある関数を書き換えました。それを正しく行うには、おそらくコード全体を調べて短所に代わってintを使用する必要がありますが、その作業だけでは、更新するために必要なコード量と一緒にテストすることができます。 – Pavel

答えて

6

コンパイラの変更。特にgccでは、あなたが今日何を知っているかは、明日、または昨日働くことはありません。そして、コンパイラ(armcc、clangなど)間で一貫して動作することはありません。

1)shortsを削除してintsと置き換え、それを上書きしてください。これはオプションですが、最も痛みを伴う解決策です。

2)特定のasmが必要な場合は、特定のasmを書き留めてください。オプションもあります。

他のコードよりも一貫してコンパイルされたコードを書くことは非常に可能ですが、一貫してではなく、常に正確にコードシーケンスを取得することはできません。あなたは長期的には自分自身を傷つけているだけでなく、自分のasm解決策を書いています。あなたが実際に探している解決策は、コードを通過し、shortをintに置き換えることです。これは、そこで短絡するよりも一貫してコンパイルされるコードを生成することになります。コンパイラの変更に伴い、すべての時間が短縮され、数か月ごとに書き直す必要はありません。

これを完全に制御するには、asmにコンパイルして問題の命令を逆アセンブルして削除し、その関数をasmにしておきます。タスクを完了するのが速くて簡単で、このオーバーヘッドを削除したいと思ってもらいたいです。実際には、あなたがarmccでコンパイルしたいものをarmccに持っているので、gnuアセンブラの習慣の愚かさにパッチを当てて、それを1つの解決策として使用します(少なくともアームツールとgnuの両方をアセンブルするasmを書くことができます腕の広告の日には、私はツールにアクセスする前に多くのrvct時間を持っていませんでした)。

正確な結果を得るために提供した正確な例を得るにはいくつかの方法がありますが、真剣にそれがあなたの後ろであることは疑問です。あなたはasmの2行を書いて、 。私の推測では、関数を(CLZより大きい)インラインでインライン化しようとしていますが、それをintと呼ぶときには、インラインasmなしであなたが望むものを与えます。 (インラインasmは、変数宣言の変更、型の変更、読み込みとテストの同じ量のコードを変更するよりも実装とテストに要する時間が短くても、インラインasmはどのように見えるのでしょうか?だからここ

はあなたの現実です:

1)ショートパンツとその副作用

2と一緒に住んで)何かをするために数日または数週間または数ヶ月を取るint型に

をそれらを変更大きくはありません対処。ほとんどの場合、に何日か、何週間か、何か月かかり、何かをしないでください。とにかくそれをやる必要があるので、2xways、2xmonthsの2xdaysを持つようになりました。ソリューションの種類にかかわらず、コードを変更しなければならない、またはそれをテストする必要があります。決定。インラインasmを使用してコンパイラをハッキングすることは、最もリスクが高く、テストが時間の式の中で変化した場合に最も多くのテストが行​​われるはずです。少数のgccバージョンが必要で、6ヶ月ごとに再テストします。

通常、asmの解決策は、abiが変更されたとき、再テストの間に10年かかります。ちょうど64ビットから128ビットになるとCが20年になることを修正します。しかし、32から64ビットへの移行はまだ進んでおり、ARM32から64ビットへの移行/混合を開始していません(32ビットARMプロセッサをすべて64ビットで放棄しないでください)。バックエンドはしばらく混乱するだろう、私は今、彼らとゲームをするつもりはない。あなたがコードのintのサイズに頼っていない(どこかで最小32を必要とするが、それが64ビットきれいであることを確かめる)、きれいで、ポータブルなCを作ることは、あなたの最も安い解決策です。

+0

こんにちはdwelch、非常に長く説明的な返答をいただきありがとうございます。私はあなたのすべてのポイントを明確に理解しており、私が本当に必要としているすべてのことをやってきました。この時点で私が望むのは、GCCに、それが必要ではないことを知っている場所でSXTHを生成しないようにすることです(基本的に、オプションについて知る必要はありません。私が望むのは、コンパイラだけで適切な動作をさせることです。(将来のコンパイラがSXTHを再び追加しても、それは問題ありません)。 – Pavel

+0

要するに、ある種のgcc固有の「ハック」がキャストタイプや他のインラインasm修飾子を使ってその動作を取得することが予想されます。私は異なったキャストと修飾子を試して何も助けなかった。 – Pavel

1

それはあなたが後にしているスピードだ場合、およびないコードサイズ、あなたはこれを試すことができます。

追記
static __inline short CLZ(int n) 
{ 
    short ret; 
#ifdef __GNUC__ 
    __asm__("clz %0, %1\n" 
      "bx lr" 
      : "=r"(ret) : "r"(n)); 
#else 
    __asm { clz ret, n; } 
#endif 
    return ret; 
} 

GCCコンパイラが、ここで正しいことをやっているように私には思えます。 では(C++ではなく)shortを返す関数はありません。常に自動的にintに変換されます。だから、コンパイラをだますこと以外に選択肢はありません。ファイル名をtest.cppに変更するとどうなりますか?

+0

Tony、インラインのbx lrがオプティマイザに悪影響を及ぼすかどうか、またはそれがすべて可能であるかどうかはわかりません。明らかに、サンプルをローリングさせるだけの場合は解決策ではない:CLZの短いバージョンがどこにでも使われ、どこで使われているのかSXTHは生成されるべきではない。同じ32ビットレジスタを使用していても、短い返すものがあります。しかしgccは署名拡張が必要だと思っており、これは必要ではないことを知っています。基本的にSXTH関数は、上位16ビットがゼロまたは1であることを確認しますが、その関数への入力はすでに適切なレイアウトになっています。 – Pavel

+0

また、実際には関数のオーバーロードなどの単純な機能を得るためにC++コンパイルを使用していますが、この例ではCやC++のコンパイルでも違いはありません – Pavel

+0

gxがopcodeを実行していないようですレベル最適化:bx lrの後に同じペアを再度追加します。SXTH + 1つ以上のbx lr。つまり、test_clzがCLZ(CLZ(a))という本体を持っていた場合、結果は悪くなります:インライン化されてもGCCは依然としてbx lrを宣言します。おそらく、llvm/clangでopcodeレベルの最適化を行い、sxthが必要でないか、またはリターンがインラインasm自体から行われるかを検出する可能性があります。 – Pavel

関連する問題