GNURX用のCCRXmachine.hとCCRXmachine.cというソースがe2 studioフォルダにありました(内容は概ね名前から予想される通りのものでした)

こんにちは。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.h



e2 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 命令も吐けて良いと思うのだけどなあ。

  • LEONです。
    Myマクロですがどうでしょうか。

    #define SWAP(a, b) (a)^=(b); (b)^=(a); (a)^=(b); // スワップ (a ⇔ b)
  • fujitaさん
    > ただの関数として用意
    > bsr.a c <_hoge+0xc>
    あ゛~~ インライン展開もされてないのか。そりゃダメだわ。改善要望します。
  • ほやです。自己レスで済みません。
    もうちょっと調べたら、リンク時最適化 (リンカの -flto オプション)が有効になっていれば、ただの関数のままでもインライン展開されました。逆に-fltoがないとinline宣言してもインライン展開されないこともあったり、他の最適化オプションとの組み合わせも考えて使わないといけないみたいですね。
  • >  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.pdf
    xchg()関数の備考に以下の記述あり(私が紫枠で囲った部分)

    生成されるXCHG命令は、data2が指す位置のメモリオペランドを持ちます。



    RXファミリ ユーザーズマニュアル ソフトウェア編
    www.renesas.com/ja-jp/doc/products/mpumcu/doc/rx_family/r01us0032jj0120_rxsm.pdf
    XCHG命令の説明に以下の記述あり(私が赤枠で囲った部分)(紫枠で囲った部分は先程のxchg()関数の紫枠と対応)

    実装により、排他制御に使える場合があります。詳細については、各製品のハードウェアマニュアルを参照してください。



    実は、xchg()関数の2つの引数のdata1とdata2に関しては、どちらがXCHG命令のメモリオペランドでどちらがレジスタオペランドなのかを把握しないと、xchg()関数でセマフォのロックを正しく行うことが出来ません。逆に言えば、xchg()関数が、単にデータ交換を行うことしか意図されていない関数なら、引数とオペランドの対応関係はマニュアルに記載する必要は無いのです。つまり、それが記載されているということから、xchg()関数は、ただ単にデータ交換を行うことだけを意図されている関数では無い、ということが分かるのです。

  • NoMaYさん、fujitaさん

    こんにちは、シェルティです。

    本件、なんらか見解だすように関係者に依頼しました。進展ありましたら、書き込みます。
    私としてはfujitaさんのコードを暫定として適用するのが今の対策としてよいと思いました。
    ご協力に感謝いたします。

    以上です
  • NoMaYさん
    ほやです。
    > xchg()関数でセマフォのロックを正しく行うことが出来ません。
    まあまあ、
    XCHG命令として吐かないと「そういう目的には」使えない、って話は皆さん解っているとは思いますよ。

    ・GCCで実装されていないのだから体裁だけでもあるだけマシ
    ・体裁だけあっても紛らわしいだけ
    どちらと見るかは何に使おうとしているかに寄るのかと。