コンパイラがLSRを直接使用しないのはなぜですか


10

こんにちは、タイミングが非常に重要なArduino Uno(ATmega328p)を使用するプロジェクトに取り組んでいるため、コンパイラーがコードを変換する命令を確認したいと思いました。そしてそこに私はuint8_t使用する各反復で右に1ビットシフトするものを持っています、そしてdata >>= 1コンパイラーはこれを5つの命令に翻訳したようです(にdataありますr24):

mov     r18, r24
ldi     r19, 0x00
asr     r19
ror     r18
mov     r24, r18

しかし、命令セットのドキュメントを見ると、これを正確に実行する命令が見つかります。 lsr r24

私は何かを見落としたり、コンパイラがこれも使用しないのはなぜですか?レジスタr18r19は他では使用されません。

私はArdunioを使用していますが、正しければ通常のavr-gccコンパイラを使用します。これは、シーケンスを生成するコード(トリミング)です。

ISR(PCINT0_vect) {
    uint8_t data = 0;
    for (uint8_t i = 8; i > 0; --i) {
//        asm volatile ("lsr %0": "+w" (data));
        data >>= 1;
        if (PINB & (1 << PB0))
            data |= 0x80;
    }
    host_data = data;
}

私が見る限り、Ardunino IDEはバージョン6.2.0-1.fc24のシステムによって提供されるAVR gccコンパイラを使用しています。どちらもパッケージマネージャーを介してインストールされるため、最新の状態である必要があります。


1
アセンブリはCコードに対応していないようです。
Eugene Sh。

Ardunio IDEを使用してコンパイルしてavr-objdumpから、elfファイルで使用しました…対応していないように見えるのは何ですか?
xZise 2017

1
@Eugene Shが:これはない Cコードに対応します。それはちょうど行に対応しますdata >>= 1;
カード

1
これは、「除算の代わりにシフトを使用する」が間違ったアドバイスである場合の1つです。代わりに/ = 2を実行すると、コンパイラはlsr r24を生成します。(ヒント:gccエクスプローラーでasmコード生成を試してみてください)
PlasmaHH 2017

どのコンパイラー?どんなプロセッサー?これは、質問が意味をなすために必要な情報であることは明らかです。
Olin Lathrop、2017

回答:


18

C言語の仕様によると、サイズがint(特定のコンパイラに依存します。この場合intは16ビット幅です)のサイズよりも小さい値は、操作(の場合>>)に含まれint、操作の前にアップキャストされます。
コンパイラのこの動作は、整数昇格と呼ばれます。

そして、それはまさにコンパイラがしたことです:

  • r19 = 0は、整数の昇格された値のMSByteですdata
  • (r19、r18)は、整数の昇格された値の合計を表し、とdataによって1ビット右にシフトされます。 asr r19ror 18
  • その後、結果は暗黙的にuint8_t変数にキャストバックされますdata
    mov r24, r18つまり、r19のMSByteは破棄されます。

編集:
もちろん、コンパイラーはコードを最適化できます。
問題を再現しようとすると、少なくともavr-gccバージョン4.9.2では問題が発生しないことがわかりました。これは非常に効率的なコードを作成します。つまり、C行 data >>= 1;は1つのlsr r24命令にコンパイルされます。おそらくあなたは非常に古いコンパイラバージョンを使用しているでしょう。


2
アセンブラーレベルでデバッグするために最適化されていないコードが必要になる場合があるため、これは完全な無駄ではありません。次に、最適化されていないコードがある場合は非常にうれしいです。
カード、

3
私が正しく思い出せば、-mint8は整数を8ビットにするフラグです。ただし、これには多くの望ましくない副作用があります。申し訳ありませんが、彼らが今何であったかを完全に思い出すことはできませんが、私はそれらのためにフラグを使用したことはありません。何年も前に、avr-gccを商用コンパイラと比較するのに多くの時間を費やしました。
Jon

1
そうです、C標準では少なくとも16ビットの整数が必要なので、-mint8を使用するとすべてのライブラリが壊れます。
Jon

9
ナイジェルジョーンズは、「8ビットマイクロコントローラーの効率的なCコード」で次のように述べています。
Dirceu Rodrigues Jr 2017

1
@Jonas Wielicki:問題の最善の解決策は、より優れたコンパイラを使用することです。たとえば、avr-gccバージョン4.9.2では問題を再現できません。Cコード行の場合、d >>= 1;1つのlsr r24命令しか取得できません。たぶん、xZiseは非常に古いコンパイラバージョンを使用しています。
カードの
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.