4

次の x86 コード例を検討してください。

#include <stdlib.h>

static int i;

static inline __attribute__((always_inline)) test(int x)
{
    asm volatile("mov %1, %0" : "=r"(i): "i"(x));
}

int main(void)
{
    test(5);

    return i;
}

私がそれを構築する場合:

gcc -O test.c

それはうまく構築されます。

(最適化なし)でビルドした場合:

gcc test.c

'5'値が即時値としてインライン関数テストに伝播されないため、アセンブリ段階で失敗し、制約に失敗します。

デバッグを容易にするために、関連のない他の最適化をオンにせずにこのコードをコンパイルできるようにしたいと考えています。

理論的には、詳細な GCC マニュアル-Oに記載されている一連の GCC 最適化オプションを一度に有効にする簡単な方法です。残念ながら、この動作をオンにする特定の GCC フラグを見つけることができませんでした。

何か案は?

明確化: 疑問を解消するために、コード スニペットは単なる例です。私がやろうとしていることを示すことを除けば、それ自体ではあまり意味がありません。実際の使用例には、C コンストラクトでラップしようとしている引数として即値のみを使用できるカスタム プロセッサの命令が含まれます。マクロは確かにそのトリックを行いますが、マクロの通常のすべての欠点に悩まされているため、私はそれを避けようとしています.

更新:疑問に思った人のために、マクロも機能しません。ここではインライン関数はまったく役割を果たしていないようです。たとえば、これも機能しません:

void foo (void)
{
  int i = 6;

  asm volatile ("" : : "i" (i));
}

これを反映するように質問のタイトルも修正しました。

4

3 に答える 3

6

-ftree-ter (SSA->通常パスの一時的な式を置き換えます-それが何であれ)のように見え ます:

gcc -ftree-ter test.c   # no errors

これが私がそれを決定した方法です:

  1. gcc -Q --help=optimizersデフォルトで有効/無効になっている最適化を示します (一部は有効になっています)。
  2. gcc -O -Q --help=optimizersどの最適化が有効/無効になっているかを示します-O
  3. これらのコマンドの出力をファイルにリダイレクトし、それらを比較します。
  4. が指定されている場合にのみ有効になる最適化を、-Oうまくいくまで試してください。
于 2012-07-17T08:01:09.330 に答える
2

おそらく、"i"制約を乱用しているだけです。最適化しないと、コンパイラーがこれが最後にすぐに行われることを「知る」方法はありません。

これをどれだけ最適化できるかを決定するために、gccに作業を任せるべきだと思います。"g"の代わりに制約として使用します"i"。最適化をオンにしてコンパイルすると、すべてがすぐに正常に解決されると確信しています。ただし、作成されたアセンブラを確認することをお勧めします。

于 2012-07-17T08:09:50.440 に答える
2

always_inline奇妙な属性であり、非常に GCC 固有であり、おそらく GCC バージョン固有です (したがって、詳細な動作は GCC 4.5 と GCC 4.7 で同じではない可能性があります)。

GCC は多くの最適化パスを実行することで機能しています (-O0これらのパスの一部が実行されていても、コードは発行されません)。通常、GCC-O1コンパイルでは 200 の最適化パスが実行されます。

あなたgcc-4.7のコードではコンパイルさえしないでください-O0

alw.c: In function ‘main’:
alw.c:7:5: warning: asm operand 1 probably doesn’t match constraints [enabled by default]
alw.c:7:5: error: impossible constraint in ‘asm’

GCC が何をしているかをより理解するために、それを実行するとgcc -fdump-tree-all、ほとんどの GCC パスのいわゆる「ダンプ ファイル」(パスによって変換された内部表現の一部のテキスト表現) を取得できます。このようなダンプ ファイルは何百もあることに注意してください (悲しいことに、ダンプ ファイルの名前に含まれる数字は重要ではありません)。

なぜそんなことをしたいのか理解できません。マクロを作成するか、常に最適化することをお勧めします(最近の GCC は と の両方をtestうまく処理します)。-g-O1

考えられる代替手段は、プラグイン、またはより適切なMELT 拡張機能を使用して GCC を拡張することです (MELT は GCC を拡張するための高レベルのドメイン固有言語であり、GPLv3 ライセンスの GCC プラグインとして実装されます)。次に、test関数を独自の GCCビルトインにすることができます。これは、GCC を拡張してビルトインとプラグマを追加できるためです。拡張機能は、特定のビルトインをインストールし、それらを適切に処理するためにいくつかの特定のパスを挿入します。(これは、GCC の内部をよく知っている場合でも、数日間の作業を意味します)。ビルトインは、通常、追加のターゲットプロセッサ固有の命令をインターフェイスするために使用されることに注意してください (ユース ケースと同様)。

最近の GCC (特に 4.6 と 4.7) はプラグインを受け入れます (プラグインが で構成されている場合--enable-plugins)。gcc -v特定の GCC がプラグインを受け入れているかどうかを確認してください。一部のディストリビューションは GCC プラグインのアイデアを好まないため (Suse やおそらく Redhat など)、GCC を受け入れるプラグインが含まれていません。

特定の Linux ディストリビューション (最近のもの) が GCC プラグインをまだサポートしていない場合は、バグ レポートを開いて、GCC 内でプラグインを有効にするようリクエストすることをお勧めします。GCC クロスコンパイラのサプライヤがプラグインをサポートしていない場合は、その機能を照会することもお勧めします。この機能は、数年前から FSF GNU Gcc に存在します (4.5 など)。

Debian または Ubuntu では、gcc-4.6-plugin-devorgcc-4.7-plugin-devパッケージをインストールすることをお勧めします。その後、 MELTプラグインをビルドして使用できるようになります (GCC 4.6 & 4.7 用の MELT 0.9.6 をすぐに、つまり 2012 年 7 月にリリースする予定です)。

GCC 4.6 または 4.7 を搭載した最新のディストリビューション (Debian、Ubuntu、Mandriva、ArchLinux など) には、プラグインで拡張可能な GCC があります。MELT はそのようなプラグインです (メタプラグインです。なぜなら、melt.soそれ自体がいくつかのことを行っているからですdlopen)。プラグインを受け入れる GCC があり、いくつかのプラグイン (MELT など) をインストールするgcc -fplugin=meltと、他のプラグイン固有のオプション ( MELT-fplugin-arg-melt-mode=の your-melt-modeなど) を使用するだけで実行できます。

于 2012-07-17T08:05:59.087 に答える