こんにちは。NoMaYです。e2 studio v6.3.0がリリースされていたので、インストールして幾つかプロジェクトを作成して、いつものようにe2 studioのインストールフォルダを眺めていたら、CCRXmachine.hとCCRXmachine.cというファイルがあることに気付きました。中を見てみると、概ねファイル名から予想される通りのソースファイルでした。(今までのe2 studioのインストールフォルダを見直してみたところ、以前からあったことが分かりましたが、今まで気付きませんでした。) ただ、一部コメントアウトされているものがあったり、以前に別スレッド『GUNRX用プロジェクトのスマートコンフィグレータのBSPを見ていて気付いた変な移植コード』で話題にしたことと同じ元のコードの意図を理解していない書き換えがあったり、ちょっと惜しいような気もしました。e2 studioインストールフォルダ\internal\projectgen\rx\Generate\CCRXConversion\inc\CCRXmachine.he2 studioインストールフォルダ\internal\projectgen\rx\Generate\CCRXConversion\inc\CCRXmachine.c
NoMaYさんほやです。
>この実装はダメですね
GCC本家のRX builtin 関数にもXCHGは実装がないので、関数の形式で実装するにはそう書かざるを得なかったのでしょう。
https://gcc.gnu.org/onlinedocs/gcc/RX-Built-in-Functions.html
> この実装は駄目ですね
一時変数を使用した単なる交換では排他制御に使えないのも勿論ですが、実行効率を上げる等の目的で特別な命令を吐かせたいところで用意されてる組み込み関数をただの関数として用意している時点で呼び出しコストも発生するし何考えてんのかという感じですね。
$ cat -n hoge.c 1 #include <CCRXmachine.h> 2 3 extern signed long var0, var1, var2; 4 5 void hoge(void) 6 { 7 xchg(&var0, &var1); 8 xchg(&var1, &var2); 9 xchg(&var2, &var0); 10 } $ rx-elf-gcc -O2 -c hoge.c ; rx-elf-objdump -d hoge.o CCRXmachine.o hoge.o: file format elf32-rx-le Disassembly of section P: 00000000 <_hoge>: 0: fb 12 00 00 00 00 mov.l #0, r1 6: fb 22 00 00 00 00 mov.l #0, r2 c: 05 00 00 00 bsr.a c <_hoge+0xc> 10: fb 12 00 00 00 00 mov.l #0, r1 16: fb 22 00 00 00 00 mov.l #0, r2 1c: 05 00 00 00 bsr.a 1c <_hoge+0x1c> 20: fb 12 00 00 00 00 mov.l #0, r1 26: fb 22 00 00 00 00 mov.l #0, r2 2c: 04 00 00 00 bra.a 2c <_hoge+0x2c> CCRXmachine.o: file format elf32-rx-le Disassembly of section P: 00000000 <_xchg>: 0: ec 15 mov.l [r1], r5 2: e0 21 mov.l [r2], [r1] 4: e3 25 mov.l r5, [r2] 6: 02 rts $
ヘッダファイルに
static inline void xchg(signed long *data1, signed long *data2) __attribute__((always_inline)); static inline void xchg(signed long *data1, signed long *data2) { signed long temp = *data1; __asm __volatile( " xchg [%1], %0\n" : "+r"(temp) : "r"(data2) ); *data1 = temp; }
とかあれば、
$ cat -n piyo.c 1 #include <CCRXmachine.h> 2 3 extern signed long var0, var1, var2; 4 5 void piyo(void) 6 { 7 xchg(&var0, &var1); 8 xchg(&var1, &var2); 9 xchg(&var2, &var0); 10 } $ rx-elf-gcc -O2 -c piyo.c ; rx-elf-objdump -d piyo.o piyo.o: file format elf32-rx-le Disassembly of section P: 00000000 <_piyo>: 0: fb 32 00 00 00 00 mov.l #0, r3 6: ec 32 mov.l [r3], r2 8: fb 42 00 00 00 00 mov.l #0, r4 e: 06 a0 10 42 xchg [r4].l, r2 12: fb 52 00 00 00 00 mov.l #0, r5 18: e3 32 mov.l r2, [r3] 1a: ec 42 mov.l [r4], r2 1c: 06 a0 10 52 xchg [r5].l, r2 20: e3 42 mov.l r2, [r4] 22: ec 54 mov.l [r5], r4 24: 06 a0 10 34 xchg [r3].l, r4 28: e3 54 mov.l r4, [r5] 2a: 02 rts $
低コストで xchg 命令も吐けて良いと思うのだけどなあ。
> Myマクロですがどうでしょうか。
個人的にはオブジェクトの交換を行いたい機会がさほどあるわけではないのでそれ用のマクロを用意する意義は感じないのですが、なんらかの理由で用意をするとして、抽象化を目的とするのであれば XOR 交換アルゴリズムは使用すべきではなく一時変数を使用する方法にすべきと思います。XOR 交換アルゴリズムは整数のオブジェクトにしか使用できず浮動小数点型や構造体等に対応できません。また、GNURX では上手く最適化できないようで、一時変数を使用する方法と比べて効率も良くないようです。
$ cat -n hoge.c 1 #define SWAP(a, b) (a)^=(b); (b)^=(a); (a)^=(b); // スワップ (a ⇔ b) 2 3 void charSwap(void) 4 { 5 extern char c0, c1; 6 SWAP(c0, c1); 7 } 8 9 void shortSwap(void) 10 { 11 extern short s0, s1; 12 SWAP(s0, s1); 13 } 14 15 void longSwap(void) 16 { 17 extern long l0, l1; 18 SWAP(l0, l1); 19 } 20 21 void longLongSwap(void) 22 { 23 extern long long ll0, ll1; 24 SWAP(ll0, ll1); 25 } $ rx-elf-gcc -O2 -S hoge.c -o - .file "hoge.c" .section P,"ax" .global _charSwap .type _charSwap, @function _charSwap: mov.L #_c1, r4 mov.L #_c0, r5 mov.B [r4], r3 mov.B [r5], r2 xor r3, r2 xor r2, r3 xor r3, r2 mov.B r3, [r4] mov.B r2, [r5] rts .size _charSwap, .-_charSwap .global _shortSwap .type _shortSwap, @function _shortSwap: mov.L #_s1, r4 mov.L #_s0, r5 mov.W [r4], r3 mov.W [r5], r2 xor r3, r2 xor r2, r3 xor r3, r2 mov.W r3, [r4] mov.W r2, [r5] rts .size _shortSwap, .-_shortSwap .global _longSwap .type _longSwap, @function _longSwap: mov.L #_l1, r4 mov.L #_l0, r5 mov.L [r4], r3 mov.L [r5], r2 xor r3, r2 xor r2, r3 xor r3, r2 mov.L r3, [r4] mov.L r2, [r5] rts .size _longSwap, .-_longSwap .global _longLongSwap .type _longLongSwap, @function _longLongSwap: mov.L #_ll1, r4 mov.L #_ll0, r5 mov.L [r4], r14 mov.L 4[r4], r1 mov.L [r5], r2 mov.L 4[r5], r3 xor r14, r2 xor r1, r3 xor r2, r14 xor r3, r1 xor r14, r2 xor r1, r3 mov.L r14, [r4] mov.L r1, 4[r4] mov.L r2, [r5] mov.L r3, 4[r5] rts .size _longLongSwap, .-_longLongSwap .ident "GCC: (GCC_Build_20180316) 4.8.4.201801-GNURX" $ cat -n piyo.c 1 #define SWAP(a, b) \ 2 do { \ 3 typeof(a) _temporaryVariableForSwapping_ = (a); \ 4 (a) = (b); \ 5 (b) = _temporaryVariableForSwapping_; \ 6 } while (0) 7 8 void charSwap(void) 9 { 10 extern char c0, c1; 11 SWAP(c0, c1); 12 } 13 14 void shortSwap(void) 15 { 16 extern short s0, s1; 17 SWAP(s0, s1); 18 } 19 20 void longSwap(void) 21 { 22 extern long l0, l1; 23 SWAP(l0, l1); 24 } 25 26 void longLongSwap(void) 27 { 28 extern long long ll0, ll1; 29 SWAP(ll0, ll1); 30 } $ rx-elf-gcc -O2 -S piyo.c -o - .file "piyo.c" .section P,"ax" .global _charSwap .type _charSwap, @function _charSwap: mov.L #_c0, r4 mov.B [r4], r3 mov.L #_c1, r5 mov.B [r5], [r4] mov.B r3, [r5] rts .size _charSwap, .-_charSwap .global _shortSwap .type _shortSwap, @function _shortSwap: mov.L #_s0, r4 mov.W [r4], r3 mov.L #_s1, r5 mov.W [r5], [r4] mov.W r3, [r5] rts .size _shortSwap, .-_shortSwap .global _longSwap .type _longSwap, @function _longSwap: mov.L #_l0, r4 mov.L [r4], r3 mov.L #_l1, r5 mov.L [r5], [r4] mov.L r3, [r5] rts .size _longSwap, .-_longSwap .global _longLongSwap .type _longLongSwap, @function _longLongSwap: mov.L #_ll0, r4 mov.L [r4], r2 mov.L 4[r4], r3 mov.L #_ll1, r5 mov.L [r5], [r4] mov.L 4[r5], 4[r4] mov.L r2, [r5] mov.L r3, 4[r5] rts .size _longLongSwap, .-_longLongSwap .ident "GCC: (GCC_Build_20180316) 4.8.4.201801-GNURX" $
> 逆に-fltoがないとinline宣言してもインライン展開されないこともあったり、 関数宣言時に __attribute__((always_inline)) を指定しすると -flto に関係なくインライン展開が強制されると思いますが上手く行かないことがあるでしょうか? あるいは、インラインアセンブラを関数風のマクロで使用するというのも手だと思います。
こんにちは。NoMaYです。fujitaさん、xchg()のGNURXでの実装例は、別スレッド『Amazon FreeRTOSだそうです。ルネサスさんのRXは参加しないのかな?』でCC-RX用プロジェクトをGNURX用プロジェクトへ移植する際に参考にさせて頂こうと思います。有難う御座います。ほやさん、LEONさん、お二人のリプライの文面から察するに、別スレッド『GUNRX用プロジェクトのスマートコンフィグレータのBSPを見ていて気付いた変な移植コード』でのCC-RXによるr_bspモジュールをGNURXによるr_bspモジュールへ移植したプログラマ殿や、本スレッドでのCC-RXのxchg()関数をGNURXによるxchg()関数へ移植したプログラマ殿と、同じ勘違いをされている状態なのだと思われます。その別スレッドに私が書いた文面と一部重複するのですが、この関数は、ただ単にデータ交換を行うだけの関数では無く、RXマイコンのXCHG命令でセマフォのロックを行う操作をプログラマがアセンブラ記述しなくても行えるようにすることも意図されている関数なのです。その意図が分かるのは『CC-RXコンパイラ ユーザーズマニュアル 』と『RXファミリ ユーザーズマニュアル ソフトウェア編』の以下の画面コピーにある記述からです。CC-RXコンパイラ ユーザーズマニュアル www.renesas.com/ja-jp/doc/products/tool/doc/011/r20ut3248jj0105-ccrx.pdfxchg()関数の備考に以下の記述あり(私が紫枠で囲った部分)「生成されるXCHG命令は、data2が指す位置のメモリオペランドを持ちます。」RXファミリ ユーザーズマニュアル ソフトウェア編www.renesas.com/ja-jp/doc/products/mpumcu/doc/rx_family/r01us0032jj0120_rxsm.pdfXCHG命令の説明に以下の記述あり(私が赤枠で囲った部分)(紫枠で囲った部分は先程のxchg()関数の紫枠と対応)「実装により、排他制御に使える場合があります。詳細については、各製品のハードウェアマニュアルを参照してください。」実は、xchg()関数の2つの引数のdata1とdata2に関しては、どちらがXCHG命令のメモリオペランドでどちらがレジスタオペランドなのかを把握しないと、xchg()関数でセマフォのロックを正しく行うことが出来ません。逆に言えば、xchg()関数が、単にデータ交換を行うことしか意図されていない関数なら、引数とオペランドの対応関係はマニュアルに記載する必要は無いのです。つまり、それが記載されているということから、xchg()関数は、ただ単にデータ交換を行うことだけを意図されている関数では無い、ということが分かるのです。