こんにちは。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
GNURX の __builtin_rx_xchg() を確認してみましたが
$ cat -n xchgTest.c 1 extern int a, b; 2 3 void hoge(void) 4 { 5 __builtin_rx_xchg(&a, &b); 6 } $ rx-elf-gcc -v Using built-in specs. COLLECT_GCC=C:\Renesas\e2studio\GCC for Renesas RX 4.8.4.201801-GNURX-ELF\rx-elf\rx-elf\bin\rx-elf-gcc.exe COLLECT_LTO_WRAPPER=c:/renesas/e2studio/gcc\ for\ renesas\ rx\ 4.8.4.201801-gnurx-elf/rx-elf/rx-elf/bin/../libexec/gcc/rx-elf/4.8.4.201801-GNURX/lto-wrapper.exe Target: rx-elf Configured with: /builder/AutomatedBuilds/rx/builds/2018q1_RX_RC3/rx/source/gcc/configure --target=rx-elf --host=i586-mingw32msvc --enable-languages=c,c++ --disable-shared --with-newlib --enable-lto --enable-libssp --enable-plugins --enable-gold --disable-libstdcxx-pch --with-pkgversion=GCC_Build_20180316 --prefix=/builder/AutomatedBuilds/rx/builds/2018q1_RX_RC3/rx/rx_win Thread model: single gcc version 4.8.4.201801-GNURX (GCC_Build_20180316) $ rx-elf-gcc -O2 xchgTest.c -S -o - .file "xchgTest.c" .section P,"ax" .global _hoge .type _hoge, @function _hoge: mov.L #_a, r2 mov.L [r2], r3 mov.L #_b, r5 mov.L [r5], r4 mov.L r3, [r2] xchg r4, r3 mov.L r4, [r5] rts .size _hoge, .-_hoge .ident "GCC: (GCC_Build_20180316) 4.8.4.201801-GNURX" $
ちょっと排他制御には使えない感じですね。
こんにちは。NoMaYです。
fujita nozomu said:つーか、ただの交換も機能しない罠。
static rtxrx_expand_builtin_xchg (tree exp){ rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0)); rtx arg2 = expand_normal (CALL_EXPR_ARG (exp, 1)); /* if arg2 is a reg than we can safely use the form xchg [Rs].memex, Rd, othewise only xchg Rs, Rd */ if(REG_P(arg2)) { rtx mem1 = gen_rtx_MEM (SImode, arg1); rtx mem2 = gen_rtx_MEM (SImode, arg2); rtx mem1toreg = copy_to_reg(mem1); MEM_VOLATILE_P (mem1) = 1; MEM_VOLATILE_P (mem2) = 1; emit_insn (gen_exchangesi (mem1toreg, mem2)); emit_move_insn(mem1, mem1toreg); } else { rtx mem1 = gen_rtx_MEM (SImode, arg1); rtx mem2 = gen_rtx_MEM (SImode, arg2); rtx mem1toreg = copy_to_reg(mem1); rtx mem2toreg = copy_to_reg(mem2); MEM_VOLATILE_P (mem1) = 1; MEM_VOLATILE_P (mem2) = 1; emit_insn (gen_exchangesi (mem1toreg, mem2toreg)); emit_move_insn(mem1, mem1toreg); emit_move_insn(mem2, mem2toreg); } return NULL_RTX;}
> ひょっとして、後続の最適化処理で命令の順番が入れ替わってしまったのでは?
最適化レベル 0 や 1 でコンパイルすると効率は悪いものゝ交換自体には問題がないっぽいコードを吐くのでそれっぽい感じですね。
$ rx-elf-gcc -O0 xchgTest.c -S -o - .file "xchgTest.c" .section P,"ax" .global _hoge .type _hoge, @function _hoge: push.l r6 mov.L r0, r6 mov.L #_a, r5 mov.L [r5], r4 mov.L #_b, r5 mov.L [r5], r5 xchg r5, r4 mov.L #_a, r3 mov.L r4, [r3] mov.L #_b, r4 mov.L r5, [r4] rtsd #4, r6-r6 .size _hoge, .-_hoge .ident "GCC: (GCC_Build_20180316) 4.8.4.201801-GNURX" $ rx-elf-gcc -O1 xchgTest.c -S -o - .file "xchgTest.c" .section P,"ax" .global _hoge .type _hoge, @function _hoge: mov.L #_a, r3 mov.L [r3], r2 mov.L #_b, r5 mov.L [r5], r4 xchg r4, r2 mov.L r2, [r3] mov.L r4, [r5] rts .size _hoge, .-_hoge .ident "GCC: (GCC_Build_20180316) 4.8.4.201801-GNURX" $
自己レス
> つーか、ただの交換も機能しない罠。
https://gcc-renesas.com/ja/ で知らぬ間に GCC for Renesas 4.8.4.201803-GNURX Toolchain というのが公開されており(https://gcc-renesas.com/ja/rx-download-toolchains/)、これを早速ダウンロード、インストールしてみたところ、release_notes.pdf に変更点として
> 3. [Bug-Fix]Fixed the xchgbuiltin function.
というのがあり、期待して確認してみたところでは
$ rx-elf-gcc -v Using built-in specs. COLLECT_GCC=C:\Renesas\e2studio\GCC_for_Renesas_RX_4.8.4.201803-GNURX-ELF\rx-elf\rx-elf\bin\rx-elf-gcc.exe COLLECT_LTO_WRAPPER=c:/renesas/e2studio/gcc_for_renesas_rx_4.8.4.201803-gnurx-elf/rx-elf/rx-elf/bin/../libexec/gcc/rx-elf/4.8.4.201803-GNURX/lto-wrapper.exe Target: rx-elf Configured with: /builder/AutomatedBuilds/rx/builds/2018q3_RX_RC4/rx/source/gcc/configure --target=rx-elf --host=i686-w64-mingw32 --enable-languages=c,c++ --disable-shared --with-newlib --enable-lto --enable-libssp --enable-plugins --enable-gold --disable-libstdcxx-pch --with-pkgversion=GCC_Build_20181126 --prefix=/builder/AutomatedBuilds/rx/builds/2018q3_RX_RC4/rx/rx_win Thread model: single gcc version 4.8.4.201803-GNURX (GCC_Build_20181126) $ cat -n xchgTest.c 1 extern int a, b; 2 3 void hoge(void) 4 { 5 __builtin_rx_xchg(&a, &b); 6 } $ rx-elf-gcc -O2 xchgTest.c -S -o - .file "xchgTest.c" .section P,"ax" .global _hoge .type _hoge, @function _hoge: mov.L #_a, r3 mov.L #_b, r5 mov.L [r3], r2 mov.L [r5], r4 xchg r4, r2 mov.L r2, [r3] mov.L r4, [r5] rts .size _hoge, .-_hoge .ident "GCC: (GCC_Build_20181126) 4.8.4.201803-GNURX" $ rx-elf-gcc -O0 xchgTest.c -S -o - .file "xchgTest.c" .section P,"ax" .global _hoge .type _hoge, @function _hoge: push.l r6 mov.L r0, r6 mov.L #_a, r5 mov.L [r5], r4 mov.L #_b, r5 mov.L [r5], r5 xchg r5, r4 mov.L #_a, r3 mov.L r4, [r3] mov.L #_b, r4 mov.L r5, [r4] rtsd #4, r6-r6 .size _hoge, .-_hoge .ident "GCC: (GCC_Build_20181126) 4.8.4.201803-GNURX" $
なんと! 交換が機能するようになったようです(ヤッターオメデトーパチパチパチ
……ただ、排他制御には使えないし処理としても無駄に xchg 命令が使われてるだけなので価値はないですね。
# ゲーまた GNU Tools に報告して今度は正しく直してくれたとしても半年後とかかよ。レスポンス悪すぎて気が遠くなるな。
fujitaさんほやです。-O0 指定時のコードだけど、builtin関数を1個しか書かないとhoge関数由来のコードと、builtin関数由来のコードがどこからなのか区別が付きませんが、3つ4つ並べて書いたものを見た限りではbuiltin関数由来のコードが無用に大きいと言う訳でもなさそうです。「無駄に xchg 命令が使われてるだけ」って、どういう意味ですか?(喧嘩売ってるのでなくただ聞いているだけです念のため)
> 「無駄に xchg 命令が使われてるだけ」って、どういう意味ですか?
`-O2' 版:
_hoge: mov.L #_a, r3 mov.L #_b, r5 mov.L [r3], r2 mov.L [r5], r4 xchg r4, r2 mov.L r2r4, [r3] mov.L r4r2, [r5] rts
`-O0' 版:
_hoge: push.l r6 mov.L r0, r6 mov.L #_a, r5 mov.L [r5], r4 mov.L #_b, r5 mov.L [r5], r5 xchg r5, r4 mov.L #_a, r3 mov.L r4r5, [r3] mov.L #_b, r4r3 mov.L r5r4, [r4r3] rtsd #4, r6-r6
無駄に使われてる xchg 命令はない方が良いという意味です。
fujita nozomuさんほや です。
なるほど。意図は理解しましたが、そこまではやってくれないのではないかと思います。
ここから先はGCCが何でできているかの話になってしまうのですが、GCCではビルトイン関数をRTLで記述されたinstruction patternとして実装されます。GNURXも同様のはずです。参考:https://gcc.gnu.org/onlinedocs/gccint/RTL-Template.html
C言語部分からビルトイン関数へのパラメータ引き渡しをどうコードに展開するかはGCCに任されるので、そこはビルトイン関数の中身を工夫しても改善はされないでしょう。(RTLの書き方で工夫の余地があるかもしれませんが、余計な事やってバグが増えるのも心配…)上のコードで言えば、変数から持って来る所と変数に書き戻すコードはビルトイン関数の中身ではなくパラメータ引き渡し部に相当します(最適化で消えるのも中身ではなく引き渡しのコード)。
RTL で最小限のコードで XCHG 命令を記述できれば最適化でおかしくなることもないのでは?
RTL ではありませんが下記のインラインアセンブラは引数がレジスタで渡されてインライン展開された場合、一つの XCHG 命令になります。
$ cat -n xchg.c 1 int xchg(int a, int* b) 2 { 3 __asm __volatile( 4 "xchg [%1], %0 \n" 5 : "+r"(a) 6 : "r"(b) 7 : "memory" 8 ); 9 return a; 10 } $ rx-elf-gcc -O2 -c xchg.c ; rx-elf-objdump -d xchg.o xchg.o: file format elf32-rx-le Disassembly of section P: 00000000 <_xchg>: 0: 06 a0 10 21 xchg [r2].l, r1 4: 02 rts $
これ以上は最適化不能なので最適化の影響もないですね。RTL でも同じようなことは可能では?
$ cat -n hogera.c 1 static inline int xchg(int a, int* b) __attribute__((always_inline)); 2 static inline int xchg(int a, int* b) 3 { 4 __asm __volatile( 5 "xchg [%1], %0 \n" 6 : "+r"(a) 7 : "r"(b) 8 : "memory" 9 ); 10 return a; 11 } 12 13 extern int a, b; 14 15 void inlineAsmXchgTest1(void) 16 { 17 a = xchg(a, &b); 18 } 19 20 void builtinRxXchgTest1(void) 21 { 22 __builtin_rx_xchg(&a, &b); 23 } 24 25 void inlineAsmXchgTest2(int* a, int* b) 26 { 27 *a = xchg(*a, b); 28 } 29 30 void builtinRxXchgTest2(int* a, int* b) 31 { 32 __builtin_rx_xchg(a, b); 33 } $ rx-elf-gcc -O2 -S hogera.c -o- .file "hogera.c" .section P,"ax" .global _inlineAsmXchgTest1 .type _inlineAsmXchgTest1, @function _inlineAsmXchgTest1: mov.L #_a, r4 mov.L [r4], r5 mov.L #_b, r3 ; 4 "hogera.c" 1 xchg [r3], r5 ; 0 "" 2 mov.L r5, [r4] rts .size _inlineAsmXchgTest1, .-_inlineAsmXchgTest1 .global _builtinRxXchgTest1 .type _builtinRxXchgTest1, @function _builtinRxXchgTest1: mov.L #_a, r3 mov.L #_b, r5 mov.L [r3], r2 mov.L [r5], r4 xchg r4, r2 mov.L r2, [r3] mov.L r4, [r5] rts .size _builtinRxXchgTest1, .-_builtinRxXchgTest1 .global _inlineAsmXchgTest2 .type _inlineAsmXchgTest2, @function _inlineAsmXchgTest2: mov.L [r1], r5 ; 4 "hogera.c" 1 xchg [r2], r5 ; 0 "" 2 mov.L r5, [r1] rts .size _inlineAsmXchgTest2, .-_inlineAsmXchgTest2 .global _builtinRxXchgTest2 .type _builtinRxXchgTest2, @function _builtinRxXchgTest2: mov.L [r1], r5 xchg [r2].L, r5 mov.L r5, [r1] rts .size _builtinRxXchgTest2, .-_builtinRxXchgTest2 .ident "GCC: (GCC_Build_20181126) 4.8.4.201803-GNURX" $ rx-elf-gcc -O0 -S hogera.c -o- .file "hogera.c" .section P,"ax" .global _inlineAsmXchgTest1 .type _inlineAsmXchgTest1, @function _inlineAsmXchgTest1: push.l r6 add #-8, r0, r6 mov.L r6, r0 mov.L #_a, r5 mov.L [r5], r5 mov.L r5, [r6] mov.L #_b, 4[r6] mov.L 4[r6], r4 mov.L [r6], r5 ; 4 "hogera.c" 1 xchg [r4], r5 ; 0 "" 2 mov.L r5, [r6] mov.L [r6], r5 mov.L r5, r4 mov.L #_a, r5 mov.L r4, [r5] rtsd #12, r6-r6 .size _inlineAsmXchgTest1, .-_inlineAsmXchgTest1 .global _builtinRxXchgTest1 .type _builtinRxXchgTest1, @function _builtinRxXchgTest1: push.l r6 mov.L r0, r6 mov.L #_a, r5 mov.L [r5], r4 mov.L #_b, r5 mov.L [r5], r5 xchg r5, r4 mov.L #_a, r3 mov.L r4, [r3] mov.L #_b, r4 mov.L r5, [r4] rtsd #4, r6-r6 .size _builtinRxXchgTest1, .-_builtinRxXchgTest1 .global _inlineAsmXchgTest2 .type _inlineAsmXchgTest2, @function _inlineAsmXchgTest2: push.l r6 add #-16, r0, r6 mov.L r6, r0 mov.L r1, 8[r6] mov.L r2, 12[r6] mov.L 8[r6], r5 mov.L [r5], r5 mov.L r5, [r6] mov.L 12[r6], r5 mov.L r5, 4[r6] mov.L 4[r6], r4 mov.L [r6], r5 ; 4 "hogera.c" 1 xchg [r4], r5 ; 0 "" 2 mov.L r5, [r6] mov.L [r6], r5 mov.L r5, r4 mov.L 8[r6], r5 mov.L r4, [r5] rtsd #20, r6-r6 .size _inlineAsmXchgTest2, .-_inlineAsmXchgTest2 .global _builtinRxXchgTest2 .type _builtinRxXchgTest2, @function _builtinRxXchgTest2: push.l r6 add #-8, r0, r6 mov.L r6, r0 mov.L r1, [r6] mov.L r2, 4[r6] mov.L [r6], r5 mov.L [r5], r4 mov.L 4[r6], r5 mov.L [r5], r5 xchg r5, r4 mov.L [r6], r3 mov.L r4, [r3] mov.L 4[r6], r4 mov.L r5, [r4] rtsd #12, r6-r6 .size _builtinRxXchgTest2, .-_builtinRxXchgTest2 .ident "GCC: (GCC_Build_20181126) 4.8.4.201803-GNURX" $
>RTL で最小限のコードで XCHG 命令を記述できれば最適化でおかしくなることもないのでは?RTL(instruction pattern)の中には最適化は及びません。修正前後のコードを比較した限りでの推測ですが、最適化で問題が出たのは渡されたパラメータに書き戻す手順をRTLの中で記述していなかったからだと思います。
> RTL でも同じようなことは可能では?可能ではあるでしょう。RTLの記述で明示的にレジスタ渡しやアドレス渡しに限定するなど、渡されたパラメータの属性毎に書き分けをすれば出力コードはもっと短くなると思います。(書き分け方はこの辺にも書いてあります。難しそう→ https://gcc.gnu.org/onlinedocs/gccint/Expander-Definitions.html)しかしそういう事をやり始めると書き分けのケースから漏れたパターンは正しく処理されないし、他のinstruction patternも同じようにしなきゃならなくなったり、なんだか大変な事になりそうな気がします。「頑張ってみたけど、最適化に任せた方がマシだった」という結果になるかも。