2016-10-29 7 views
0

私はこのコードを持っている:AVR GCC、アセンブリCスタブ関数、EOR及び必要な一定値

uint16_t swap_bytes(uint16_t x) 
{ 
    asm volatile(
     "eor, %A0, %B0"  "\n\t" 
     "eor, %B0, %A0"  "\n\t" 
     "eor, %A0, %B0"  "\n\t" 
     : "=r" (x) 
     : "0" (x) 
    ); 
    return x; 
} 

-std=gnu99 -save-tempsとavr- gcc version 4.8.1によって)変換される:

.global swap_bytes 
    .type swap_bytes, @function 
swap_bytes: 
/* prologue: function */ 
/* frame size = 0 */ 
/* stack size = 0 */ 
.L__stack_usage = 0 
/* #APP */ 
; 43 "..\lib\own\ownlib.c" 1 
    eor, r24, r25 
    eor, r25, r24 
    eor, r24, r25 

; 0 "" 2 
/* #NOAPP */ 
    ret 
    .size swap_bytes, .-swap_bytes 

しかし、コンパイラはそのような不平を言っています:

|65|Error: constant value required| 
|65|Error: garbage at end of line| 
|66|Error: constant value required| 
|66|Error: garbage at end of line| 
|67|Error: constant value required| 
|67|Error: garbage at end of line| 
||=== Build failed: 6 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===| 

上記の行は、 eorコマンドを使用します。なぜコンパイラはそれに問題がありますか?レジスタはほぼすべての操作が可能な上位(> = r16)です。 constant value requiredそれはリテラルを期待するような私の音...私はそれを得ることはありません。

+0

gccには組み込み機能があります。なぜそれらを使用しない?とにかくコンパイラに依存しています。プレーンCを使わないのはなぜですか? – Olaf

+0

私はオラフと付き合っています。可能であれば、ビルトインを使用してください。しかし、インラインasmを使用しなければならない場合は、あなたの問題が「余分な」カンマであるのだろうかと思います。グーグルでは、「eor r4、r4」と「eor r0、r22」(eorコマンドの後にカンマはありません)になります。私は専門家ではありませんが、それは私が最初に試してみるものです。 –

+0

f#* k!あなたが正しい。 '、'はありません。とにかくAVRはマイクロコントローラなので、プログラム空間は狭いです。 3命令はCにとって無敵です。もう一度皆さんに感謝してください! – milkpirate

答えて

0

ただ、将来のGooglerのために明確にする:

eor, r24, r25 

はEOR後に余分なコンマがあります。これは、のように記述する必要があります。

eor r24, r25 

私はまた、GCCの__builtin_bswap16を使用することを検討するために(再び)ことをお勧めします。 gccの組み込み関数に慣れていない場合は、コンパイラに組み込まれている関数であり、(関数のように見えますが)通常はインライン展開されます。彼らは、さまざまなプロセッサのすべての機能を理解し、考慮していないことを考慮に入れることができる人々によって書かれ、最適化されています。

私はできるだけコードを小さくしたいと考えています。そして、私は、あなたの特定のプロセッサ上の(何とか)この組み込み関数が準最適なコードを生成している可能性があることを承知しています。一方、まったく同じコードを生成することがあります。または、これを行うにはもっと巧妙なトリックを使うかもしれません。または、パイプライン処理(または私が 'avr'を話さないために聞いたことのない他のavr固有のもの)を利用するために、周囲のコードからの命令をインターリーブするかもしれません。

多くはである何、このコードを考えてみます。

int main() 
{ 
    return __builtin_bswap16(12345); 
} 

あなたのコードは常にスワップを処理するために、3つの手順を取ります。しかし、組み込み関数では、コンパイラはargが定数であることを認識し、実行時ではなくコンパイル時に値を計算します。それ以上に効率的ではありません。

「サポートがより簡単」というメリットも指摘できます。インラインasmを書くことは正しく行うには難しいです。そして、将来のメンテナーは、それがどのように動作するかは決して確かではありません。もちろん、組み込みのプラットフォームは、より多くのプラットフォーム間で移植可能になります。

まだ納得できませんか?私の最後のピッチ:あなたがコンマを修正した後でさえ、あなたのインラインasmコードはまだかなり正しくありません。ので、あなたが二回、gccが値を計算しなければなりません(すなわちvolatileを使用して)書かれたswap_bytesを書かれている方法(volatileの定義を参照)の

int main(int argc, char *argv[]) 
{ 
    return swap_bytes(argc) + swap_bytes(argc); 
} 

:このコードを考えてみましょう。 volatileを省略した場合(またはこれを正しく実装している組み込み関数を使用した場合)、argcは最初の呼び出しからの出力を変更して再利用しないことに気がつきました。インラインasmを正しく書くことが難しいと言いましたか?

私はあなたのコード、制約、専門知識のレベルまたは要件を知らない。たぶん、あなたのソリューションは本当に最高です。私ができることは、プロダクションコードでインラインasmを使用する前に、あなたが長くて難しいと思うように促すことです。

関連する問題