9

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

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

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

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

複数のコンパイラ用にコンパイルし、arm の armcc コンパイラ用に解決できましたが、GCC では解決できません (4.4.3 または 4.6.3 でコンパイルします)。armcc では、インライン asm ステートメント内で short 型を使用します。gccでは、短いコンパイラを使用しても、何らかの理由で符号拡張が必要であると考えています。

これは、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);
}



armcc -c -O3 で得られる期待される結果は次のとおりです。

test_clz:
    CLZ      r0,r0
    BX       lr

GCC -c -O3 が私に与える受け入れられない結果は次のとおりです。

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

int ret;また、ARMCCの代わりに内部変数を使用して CLZ を書き換えるとshort ret;、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

4

2 に答える 2

6

コンパイラが変わります。特に gcc では、今日見つけたトリックは、明日、または昨日は機能しません。また、コンパイラ間で一貫して動作しません (armcc、clang など)。

1) ショーツを取り外して int に置き換え、それで解決します。これはオプションであり、最も痛みの少ない解決策です。

2) 特定の asm が必要な場合は、特定の asm を書きます。いじらないでください。また、オプション。

一貫して他のコードよりも優れたコンパイルを行うコードを作成することは非常に可能ですが、一貫性がなく、常に希望どおりのコード シーケンスを取得できるとは限りません。独自の asm ソリューションを作成したとしても、長期的には自分自身を傷つけています。実際に探している解決策は、コードを調べてショートを int に置き換えることです。これにより、ショートをそこに置くよりも一貫してより適切にコンパイルされるコードが生成されます。全体的に時間がかからず、コンパイラーが変更されるたびに数か月ごとに書き直す必要はありません。

これを完全に制御するには、asm にコンパイルするか、問題のある命令を逆アセンブルして削除し、関数を asm に残します。タスクをすばやく簡単に完了できるため、このオーバーヘッドを取り除きたいと思うようになり、あまり保守しにくいものが残るだけです。実際には、armcc で asm にコンパイルしたいことを行う armcc があるので、gnu アセンブラーの習慣の愚かさを修正し、それを 1 つの解決策として使用します (少なくとも、ARM ツールと gnu の両方でアセンブルする asm を作成することは可能です)。アーム広告の時代には、ツールへのアクセスを失う前に rvct の時間があまりありませんでした)。

正確な結果を得るために提供した正確な例を取得する方法はいくつかありますが、それがあなたが求めているものであるとは思えません.asmの2行を書いて完了です. 私の推測では、int を呼び出すと、インライン asm なしで必要なものが得られます。(変数宣言を変更するよりも実装とテストにかかる時間が短く、タイピングがはるかに少なく、同じ量のコードを読み取ってテストするよりも、短所がある場合はどこにインライン asm がどのようにかかるかはまだわかりません)。

だからここにあなたの現実があります:

1) ショートパンツとその副作用と一緒に暮らす

2)それらをintに変更します

何かを行うのに数日、数週間、または数か月かかることは大したことではありません。ほとんどの場合、何かを回避するには数日、数週間、数か月かかります。とにかくそれをしなければならないので、今では 2xdays、2xweeks、2xmonths があります...どのソリューションでもテストする必要がある、またはテストする必要があります。コードを変更しているため、これはさまざまな要因ではありません。決断。インライン asm を使用してコンパイラをハッキングすることは、最大のリスクであり、テストが時間方程式で変化する場合、最も多くのテストが行​​われるはずです。いくつかの gcc バージョンが必要で、さらに 6 か月ごとに再テストします。

通常、asm ソリューションは abi が変更されたときで、再テストの間隔はおそらく 10 年で、C を修正するだけで、64 ビットから 128 ビットに移行するときはおそらく 20 年になります。しかし、32 ビットから 64 ビットへの移行はまだ進行中であり、ARM の 32 ビットから 64 ビットへの移行/混合は開始されていません (すべての 64 ビットに対して 32 ビット アーム プロセッサを放棄することはありません。両方とも残ります)。バックエンドはしばらく混乱するだろう。今はゲームをプレイしないだろう. コード内のintのサイズに依存しない、クリーンでポータブルなCを作成する(最小32を想定/必要とするが、64ビットがクリーンであることを確認する)のが最も安価なソリューションです。

于 2012-06-03T06:34:59.260 に答える
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(とは対照的に)ではC++、 a を返す関数などはありません。short常に自動的に に変換されintます。したがって、コンパイラをだます以外に選択肢はありません。ファイル名を に変更するとどうなりますtest.cppか?

于 2012-06-03T07:01:42.663 に答える