12

次のアセンブラ警告を取り除く方法を知っている人はいますか?

コードは x86、32 ビットです。

int test (int x)
{
  int y;
  // do a bit-rotate by 8 on the lower word. leave upper word intact.
  asm ("rorw $8, %0\n\t": "=q"(y) :"0"(x));
  return y;
}

コンパイルすると、次の(非常に有効な)警告が表示されます。

Warning: using `%ax' instead of `%eax' due to `w' suffix

私が探しているのは、%0 の下位 16 ビット サブレジスタにアクセスしたいことをコンパイラ/アセンブラに伝える方法です。バイト サブレジスタ (この場合は AL と AH) へのアクセスについても知っておくとよいでしょう。

既に "q" 修飾子を選択しているため、コンパイラは EAX、EBX、ECX、または EDX を使用する必要があります。コンパイラーがサブレジスターを持つレジスターを選択する必要があることを確認しました。

特定のレジスター (およびそのサブレジスター) を使用するように asm コードに強制できることはわかっていますが、レジスター割り当てのジョブはコンパイラーに任せたいと考えています。

4

5 に答える 5

20

%w0私の記憶が正しければ使えます。私もちょうどそれをテストしました。:-)

int
test(int x)
{
    int y;
    asm ("rorw $8, %w0" : "=q" (y) : "0" (x));
    return y;
}

編集:OPに応じて、はい、次のこともできます:

int
test(int x)
{
    int y;
    asm ("xchg %b0, %h0" : "=Q" (y) : "0" (x));
    return y;
}

x86 については、マニュアルの Extended Asm 部分のx86 Operand Modifiers セクションに記載されています。

非 x86 命令セットの場合.md、GCC ソース内のファイルを掘り下げる必要がある場合があります。たとえば、gcc/config/i386/i386.md公式に文書化される前にこれを見つける唯一の場所でした.

(関連: GNU C インライン asm では、単一オペランドの xmm/ymm/zmm のサイズ オーバーライド修飾子は何ですか?ベクトル レジスタの場合。)

于 2008-09-23T02:01:58.397 に答える
9

かなり前のことですが、今後の参考のためにこれが必要になる可能性があります...

クリスの素晴らしい答えに追加すると、キーは「%」と出力オペランドの数の間の修飾子を使用しています。たとえば、 に"MOV %1, %0"なる場合があり"MOV %q1, %w0"ます。

Constraints.md には何も見つかりませんでしたが、/gcc/config/i386/i386.cprint_reg()のソースに次の潜在的に役立つコメントがありました。

/* Print the name of register X to FILE based on its machine mode and number.
   If CODE is 'w', pretend the mode is HImode.
   If CODE is 'b', pretend the mode is QImode.
   If CODE is 'k', pretend the mode is SImode.
   If CODE is 'q', pretend the mode is DImode.
   If CODE is 'x', pretend the mode is V4SFmode.
   If CODE is 't', pretend the mode is V8SFmode.
   If CODE is 'h', pretend the reg is the 'high' byte register.
   If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op.
   If CODE is 'd', duplicate the operand for AVX instruction.
 */

例を提供するための以下のコメントix86_print_operand()

b -- 指定されたオペランドのレジスターの QImode 名を出力します。

operands[0] が reg 0 の場合、%b0 は %al を出力します。

GCC InternalsドキュメントのOutput Templateの下に、さらにいくつかの便利なオプションがリストされています。

'%cdigit' は、通常即値オペランドを示す構文を使用せずに、定数値であるオペランドを置換するために使用できます。

'%ndigit' は '%cdigit' に似ていますが、印刷前に定数の値が否定される点が異なります。

'%adigit' を使用すると、実際のオペランドがアドレスとして扱われ、メモリ参照であるかのようにオペランドを置き換えることができます。これは、「ロード アドレス」命令を出力する場合に便利です。このような命令のアセンブラ構文では、メモリ参照であるかのようにオペランドを記述する必要があることが多いためです。

'%ldigit' は、label_ref をジャンプ命令に置き換えるために使用されます。

'%=' は、コンパイル全体で各命令に固有の番号を出力します。これは、複数のアセンブラ命令を生成する単一のテンプレートでローカル ラベルを複数回参照する場合に便利です。

' %c2' コンストラクトを使用すると、オフセットを使用して LEA 命令を適切にフォーマットできます。

#define ASM_LEA_ADD_BYTES(ptr, bytes)                            \
    __asm volatile("lea %c1(%0), %0" :                           \
                   /* reads/writes %0 */  "+r" (ptr) :           \
                   /* reads */ "i" (bytes));

「 」内の重要だがまばらに文書化されている「c」に注意してください%c1。このマクロは、

ptr = (char *)ptr + bytes

ただし、通常の整数演算実行ポートは使用しません。

編集して追加:

x64 で直接呼び出しを行うのは、文書化されていない別の修飾子 ' %P0' (PIC 用のようです) が必要なため、難しい場合があります。

#define ASM_CALL_FUNC(func)                                         \
    __asm volatile("call %P0") :                                    \
              /* no writes */ :                                     \
              /* reads %0 */ "i" (func))                           

大文字の「P」のみが ICC で認識されますが、小文字の「p」修飾子も GCC で同じように機能するようです。詳細はおそらく/gcc/config/i386/i386.cにあります。"'p'" を検索します。

于 2013-07-24T04:25:31.473 に答える
3

私はそれについて考えています...クリスの2番目の解決策では、「q」制約を大文字の「Q」制約に置き換える必要があります。

int
test(int x)
{
    int y;
    asm ("xchg %b0, %h0" : "=Q" (y) : "0" (x));
    return y;
}

「q」と「Q」は、すべての整数レジスタ (ax、bx、cx、dx、si、di、sp、bp、r8-r15) の最下位バイトを取得できる 64 ビット モードではわずかに異なります。 . ただし、元の 4 つの 386 レジスタ (ax、bx、cx、dx) については、下位から 2 番目のバイト (例: ah) しか取得できません。

于 2008-09-23T17:12:58.753 に答える
0

どうやらこれを行うためのトリックがあります...しかし、それはそれほど効率的ではないかもしれません。32ビットx86プロセッサは、一般に、汎用レジスタで16ビットデータを操作するのに時間がかかります。パフォーマンスが重要な場合は、ベンチマークを行う必要があります。

これが(a)パフォーマンスに不可欠であり、(b)はるかに高速であることが証明されない限り、メンテナンスの手間を省き、Cで実行するだけです。

uint32_t y, hi=(x&~0xffff), lo=(x&0xffff);
y = hi + (((lo >> 8) + (lo << 8))&0xffff);

GCC 4.2と-O2を使用すると、これは6つの命令に最適化されます...

于 2008-09-23T06:20:31.740 に答える
0

ガチャ。何度も再利用する原始的なルーチンであれば、私はそれについて議論の余地はありません... Chris が指摘したレジスター命名のトリックは、私が覚えておかなければならない素晴らしいものです。

それが標準のGCCドキュメントにもなればいいですね!

于 2008-09-23T16:41:26.643 に答える