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



Parents
  • > この実装は駄目ですね

    一時変数を使用した単なる交換では排他制御に使えないのも勿論ですが、実行効率を上げる等の目的で特別な命令を吐かせたいところで用意されてる組み込み関数をただの関数として用意している時点で呼び出しコストも発生するし何考えてんのかという感じですね。

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

  • ヘッダファイルに
    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;
    }
    
    とかあれば、

    ↑のコード宜しくないので数日中に修正版を投稿します。

  • ほやです。

    GCC for Renesas RX のMigration guideにビルトイン関数の記述がありました。
    参照: <toolchainのインストールフォルダ>/Doc/Renesas-GNURX Migration Guide.html#_Builtin_Functions
    GCC本家に掲載されているRX対応関数より増えてます。

    で、CCRXmachine.cのxchg関数を素直に書き換えたら XCHG命令が吐かれました。

    void xchg(signed long *data1, signed long *data2)
    {
    __builtin_rx_xchg (data1, data2);
    }
    初めにこれを試すべきでした。

    ただし-fltoを付けないと関数呼び出しになってしまうのは変わりません。 関数本体の宣言の前にalways_inline 付けても効きませんでした。
    良く考えてみれば、個別に作成済みのobj同士をリンカにポイっと渡して埋め込めと言っても、それは難しいかも...
Reply
  • ほやです。

    GCC for Renesas RX のMigration guideにビルトイン関数の記述がありました。
    参照: <toolchainのインストールフォルダ>/Doc/Renesas-GNURX Migration Guide.html#_Builtin_Functions
    GCC本家に掲載されているRX対応関数より増えてます。

    で、CCRXmachine.cのxchg関数を素直に書き換えたら XCHG命令が吐かれました。

    void xchg(signed long *data1, signed long *data2)
    {
    __builtin_rx_xchg (data1, data2);
    }
    初めにこれを試すべきでした。

    ただし-fltoを付けないと関数呼び出しになってしまうのは変わりません。 関数本体の宣言の前にalways_inline 付けても効きませんでした。
    良く考えてみれば、個別に作成済みのobj同士をリンカにポイっと渡して埋め込めと言っても、それは難しいかも...
Children
  • ほやさん、fujitaさん、NoMaYさん、LEONさん

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

    種々ご検討ありがとうございます。内部検討状況を報告します。

    課題は以下3点と認識しています。

    ①GCCRX用のBSPに内蔵されるlocking.c (のR_BSP_SoftwareLock()実装)のxchg()実装
    ②CCRXmachine.cのxchg()実装
     -1: ローカル変数を使ったデータ交換形式になっている
     -2: 関数呼び出し形式なのでオーバヘッドがある
    ③GCCRXはXCHG命令を出力できない

    いくつかは対策をすでに皆様に出していただいているものがありますね。
    以下方向で進めてまいります。

    ①GCCRXでも xchg() を呼び出す
    ②-1:XCHG用のビルトイン関数を利用する
     -2:インライン展開を利用するなど性能面に気を遣った実装を考える
    ③実はGCCRXはXCHG命令を出力できる

    以上です
  • > ②-1:XCHG用のビルトイン関数を利用する

    __builtin_rx_xchg() は GCCRX の版によっては使えないので、複数の版の GCCRX をサポートしてる筈の e2studio では使用が難しいのではないかと思います。

    少なくとも手許の PC にインストールされていた 14.01 では機能せず、なんかわからん関数としてコンパイルされました。

    $ cat -n hogera.c
         1  void hogera(int* data1, int* data2)
         2  {
         3      __builtin_rx_xchg(data1, data2);
         4  }
    $ rx-elf-gcc -v
    Using built-in specs.
    COLLECT_GCC=C:\PROGRA~2\Renesas\Hew\Tools\KPIT\GNURX-~1\v14.01\rx-elf\bin\rx-elf-gcc.exe
    COLLECT_LTO_WRAPPER=c:/progra~2/renesas/hew/tools/kpit/gnurx-~1/v14.01/rx-elf/bin/../libexec/gcc/rx-elf/4.7-GNURX_v14.01/lto-wrapper.exe
    Target: rx-elf
    Configured with: /home/kpit/fsfsrc/elf-v14.01-src//gcc-4.7.3/configure --disable-shared --build=i686-pc-linux-gnu --host=i386-pc-mingw32msvc --enable-languages=c,c++ --target=rx-elf --with-newlib --with-gmp=/home/kpit/pre-requisite/gcc-4.5.x/mingw/prefix --with-mpfr=/home/kpit/pre-requisite/gcc-4.5.x/mingw/prefix --with-mpc=/home/kpit/pre-requisite/gcc-4.5.x/mingw/prefix --prefix=/usr/share/mingwgnurx_v14.01_elf-1 --enable-lto --enable-gold --disable-libstdcxx-pch : (reconfigured) /home/kpit/fsfsrc/elf-v14.01-src//gcc-4.7.3/configure --disable-shared --build=i686-pc-linux-gnu --host=i386-pc-mingw32msvc --enable-languages=c,c++ --target=rx-elf --with-newlib --with-gmp=/home/kpit/pre-requisite/gcc-4.5.x/mingw/prefix --with-mpfr=/home/kpit/pre-requisite/gcc-4.5.x/mingw/prefix --with-mpc=/home/kpit/pre-requisite/gcc-4.5.x/mingw/prefix --prefix=/usr/share/mingwgnurx_v14.01_elf-1 --enable-lto --enable-gold --disable-libstdcxx-pch : (reconfigured) /home/kpit/fsfsrc/elf-v14.01-src//gcc-4.7.3/configure --disable-shared --build=i686-pc-linux-gnu --host=i386-pc-mingw32msvc --enable-languages=c,c++ --target=rx-elf --with-newlib --with-gmp=/home/kpit/pre-requisite/gcc-4.5.x/mingw/prefix --with-mpfr=/home/kpit/pre-requisite/gcc-4.5.x/mingw/prefix --with-mpc=/home/kpit/pre-requisite/gcc-4.5.x/mingw/prefix --prefix=/usr/share/mingwgnurx_v14.01_elf-1 --enable-lto --enable-gold --disable-libstdcxx-pch : (reconfigured) /home/kpit/fsfsrc/elf-v14.01-src//gcc-4.7.3/configure --disable-shared --build=i686-pc-linux-gnu --host=i386-pc-mingw32msvc --enable-languages=c,c++ --target=rx-elf --with-newlib --with-gmp=/home/kpit/pre-requisite/gcc-4.5.x/mingw/prefix --with-mpfr=/home/kpit/pre-requisite/gcc-4.5.x/mingw/prefix --with-mpc=/home/kpit/pre-requisite/gcc-4.5.x/mingw/prefix --prefix=/usr/share/mingwgnurx_v14.01_elf-1 --enable-lto --enable-gold --disable-libstdcxx-pch
    Thread model: single
    gcc version 4.7-GNURX_v14.01 (GCC)
    
    $ rx-elf-gcc -Wall -Wextra -O2 -S -o - hogera.c
            .file   "hogera.c"
    hogera.c: In function 'hogera':
    hogera.c:3:5: warning: implicit declaration of function '__builtin_rx_xchg' [-Wimplicit-function-declaration]
            .section P,"ax"
            .global _hogera
            .type   _hogera, @function
    _hogera:
            bra     ___builtin_rx_xchg
            .size   _hogera, .-_hogera
            .ident  "GCC: (GNU) 4.7-GNURX_v14.01"
    
    $
    

    14.03 では通った。

    $ rx-elf-gcc -v
    Using built-in specs.
    COLLECT_GCC=C:\Renesas\e2studio\GNURXV~1.03-\rx-elf\rx-elf\bin\rx-elf-gcc.exe
    COLLECT_LTO_WRAPPER=c:/renesas/e2studio/gnurxv~1.03-/rx-elf/rx-elf/bin/../libexec/gcc/rx-elf/4.8-GNURX_v14.03/lto-wrapper.exe
    Target: rx-elf
    Configured with: /home/kpit/fsfsrc/elf-v14.03-src//gcc-4.8.3/configure --disable-shared --build=i686-pc-linux-gnu --host=i386-pc-mingw32msvc --enable-languages=c,c++ --target=rx-elf --with-newlib --with-gmp=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --with-mpfr=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --with-mpc=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --prefix=/usr/share//mingwgnurx_v14.03_elf-1 --enable-lto --enable-gold --disable-libstdcxx-pch --with-pkgversion=GCC : (reconfigured) /home/kpit/fsfsrc/elf-v14.03-src//gcc-4.8.3/configure --disable-shared --build=i686-pc-linux-gnu --host=i386-pc-mingw32msvc --enable-languages=c,c++ --target=rx-elf --with-newlib --with-gmp=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --with-mpfr=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --with-mpc=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --prefix=/usr/share//mingwgnurx_v14.03_elf-1 --enable-lto --enable-gold --disable-libstdcxx-pch --with-pkgversion=GCC : (reconfigured) /home/kpit/fsfsrc/elf-v14.03-src//gcc-4.8.3/configure --disable-shared --build=i686-pc-linux-gnu --host=i386-pc-mingw32msvc --enable-languages=c,c++ --target=rx-elf --with-newlib --with-gmp=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --with-mpfr=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --with-mpc=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --prefix=/usr/share//mingwgnurx_v14.03_elf-1 --enable-lto --enable-gold --disable-libstdcxx-pch --with-pkgversion=GCC : (reconfigured) /home/kpit/fsfsrc/elf-v14.03-src//gcc-4.8.3/configure --disable-shared --build=i686-pc-linux-gnu --host=i386-pc-mingw32msvc --enable-languages=c,c++ --target=rx-elf --with-newlib --with-gmp=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --with-mpfr=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --with-mpc=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --prefix=/usr/share//mingwgnurx_v14.03_elf-1 --enable-lto --enable-gold --disable-libstdcxx-pch --with-pkgversion=GCC : (reconfigured) /home/kpit/fsfsrc/elf-v14.03-src//gcc-4.8.3/configure --disable-shared --build=i686-pc-linux-gnu --host=i386-pc-mingw32msvc --enable-languages=c,c++ --target=rx-elf --with-newlib --with-gmp=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --with-mpfr=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --with-mpc=/home/vinayk/utilities/mingw_gmp_mpfr/prefix/ --prefix=/usr/share//mingwgnurx_v14.03_elf-1 --enable-lto --enable-gold --disable-libstdcxx-pch --with-pkgversion=GCC_Build_1.01
    Thread model: single
    gcc version 4.8-GNURX_v14.03 (GCC_Build_1.01)
    
    $ rx-elf-gcc -Wall -Wextra -O2 -S -o - hogera.c
            .file   "hogera.c"
            .section P,"ax"
            .global _hogera
            .type   _hogera, @function
    _hogera:
            mov.L   [r1], r14
            xchg    [r2].L, r14
            mov.L   r14, [r1]
            rts
            .size   _hogera, .-_hogera
            .ident  "GCC: (GCC_Build_1.01) 4.8-GNURX_v14.03"
    
    $
    
  • > で、CCRXmachine.cのxchg関数を素直に書き換えたら XCHG命令が吐かれました。

    > ただし-fltoを付けないと関数呼び出しになってしまうのは変わりません。 関数本体の宣言の前にalways_inline 付けても効きませんでした。

    > 良く考えてみれば、個別に作成済みのobj同士をリンカにポイっと渡して埋め込めと言っても、それは難しいかも...

    https://japan.renesasrulz.com/cafe_rene/f/forum5/5046/gnurx-ccrxmachine-h-ccrxmachine-c-e2-studio/28376#28376 の投稿で「ヘッダファイルに~」とある通り、CCRXmachine.c ではなく CCRXmachine.h に記述する話をしています。

  • fujitaさん

    シェルティです。ありがとうございます。

    なるほど、コンパイラバージョンのプリデファインマクロで切り分けて
    特定バージョン以下の場合はビルトイン関数を使わない(インライン展開でXCHG命令埋め込み)対策コード、
    特定バージョン以上はビルトイン関数を使う対策コード、とすべきですね。

    いま、専門の人が調べてくれてます。何らか対策が定まってきましたら、また報告させていただきます。

    以上です
  • ほやです。
    自己亀レスで済みません。

    > ただし-fltoを付けないと関数呼び出しになってしまうのは変わりません。 関数本体の宣言の前にalways_inline 付けても効きませんでした。
    これについて少し補足します。
    __attribute__((always_inline) の宣言は、これを宣言したソースの中に関数本体がある事を要求されます。
    現状のように xchg( )関数のプロトタイプをCCRXmachine.hに置き、本体をCCRXmachine.cに置いた状態では
    ヘッダ側にalways_inlineを付けて宣言できません。

    > 「ヘッダファイルに~」とある通り、CCRXmachine.c ではなく CCRXmachine.h に記述する話をしています。
    xchg関数1つならそれもアリなのですが、他の組み込み関数までヘッダに記述するのはムリがあるかと。

    だからと言ってCCRXmachine.cの中だけでalways_inlineを付けて宣言しても、
    別のソースからcallした場合はalways_inlineが見えていないので常にはinline展開されません。

    「always_inline 付けても効きませんでした」はそういう意味でした。

    xchg( )を関数の形でなくビルトイン関数を呼び出すマクロとして再定義した方が手間が減る気がします。
    CCRXmachine.hの中で、マクロに書き換えられるものをマクロに、
    関数でないと難しいものだけ関数で宣言してあれば良かったのではないかと思います。

    以上独り言でした。

  • > xchg関数1つならそれもアリなのですが、他の組み込み関数までヘッダに記述するのはムリがあるかと。

    えっなんで??

    > CCRXmachine.hの中で、マクロに書き換えられるものをマクロに、

    マクロよりはインライン関数の方が良いのでは。
    www.jpcert.or.jp/.../c-pre00-c.html
  • fujitaさん
    ほやです。

    >> xchg関数1つならそれもアリなのですが、他の組み込み関数までヘッダに記述するのはムリがあるかと。
    >えっなんで??
    >> CCRXmachine.hの中で、マクロに書き換えられるものをマクロに、
    >マクロよりはインライン関数の方が良いのでは。

    「関数本体をヘッダに」含めるのを嫌がる人は更に多いのでは。
    そもそもCCRXmachine.h/.cはCCRXの記述をできるだけ変更しないでGNURXに置き換えるためにあるのだから、
    関数名だけすげ替えれば済むものは、それで留めるべきだったと思います。xchg関数もその一つ。

  • > そもそもCCRXmachine.h/.cはCCRXの記述をできるだけ変更しないでGNURXに置き換えるためにあるのだから、
    > 関数名だけすげ替えれば済むものは、それで留めるべきだったと思います。xchg関数もその一つ。

    __builtin_rx_xchg() は GNURX の版によっては使えず、使える場合でも出力コードに問題があるようなので使うべきでないと思います。インラインアセンブラを使う他ないのでは。

    例えばマクロで次のように書くと

    #include <assert.h>
    
    #define xchg(data1, data2) \
    do { \
        _Static_assert(sizeof(typeof(*(data1))) == sizeof(signed long), "passing argument 1 of 'xchg' from incompatible pointer type"); \
        _Static_assert(sizeof(typeof(*(data2))) == sizeof(signed long), "passing argument 2 of 'xchg' from incompatible pointer type"); \
        signed long temp = *data1; \
        __asm __volatile( \
            "\n" \
            "\txchg\t%1, %0 \n" \
            : "+&r"(temp) \
            : "m"(*data2) \
            : \
        ); \
        *data1 = temp; \
    } while (0)
    

    引数 data1 や data2 に渡されるシンボル名が内部で使用する一時変数(↑の例ではtemp)とかち合わない運用ルールが発生します。

    あるいは次のように書いた場合、

    #include <assert.h>
    
    #define xchg(data1, data2) \
    do { \
        _Static_assert(sizeof(typeof(*(data1))) == sizeof(signed long), "passing argument 1 of 'xchg' from incompatible pointer type"); \
        _Static_assert(sizeof(typeof(*(data2))) == sizeof(signed long), "passing argument 2 of 'xchg' from incompatible pointer type"); \
        __asm __volatile( \
            "\n" \
            "\tmov.l\t%0, r5 \n" \
            "\txchg\t%1, r5 \n" \
            "\tmov.l\tr5, %0 \n" \
            : \
            : "m"(*data1), "m"(*data2) \
            : "r5" \
        ); \
    } while (0)
    

    一時変数に使用するレジスタに r5 (あるいはその他でも) を使用していますが、関数内でのレジスタの割り振りはコンパイラに任せた方が効率の良いコードを吐いてくれそうな気がする点が惜しいところですね。

    インライン関数で

    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(
            "\n"
            "\txchg\t%1, %0 \n"
            : "+&r"(temp)
            : "m"(*data2)
            :
        );
        *data1 = temp;
    }
    

    のように書けば先に挙げたマクロの問題もなく、記述もシンプルで幾らかマシなんではないでしょうか。


    >>マクロよりはインライン関数の方が良いのでは。
    >「関数本体をヘッダに」含めるのを嫌がる人は更に多いのでは。

    上記のような理屈もないところでの好き嫌いの多数決に意味はないと思います。

  • fujita nozomuさん
    ほやです。
    > インライン関数で ~ のように書けば先に挙げたマクロの問題もなく、記述もシンプルで幾らかマシなんではないでしょうか。
    いつもながら大変勉強になります。

    > 上記のような理屈もないところでの好き嫌いの多数決に意味はないと思います。
    勝負しようとは思っておりませんよ(笑)

    関数名だけ置き換える記述に留めておいたら良かった、と言うのはbuiltin関数がそのまま使える前提での発言でした。最適化時のコードに問題があると判明した今となってはアセンブラで書く以外の選択肢はないので、もはや議論の余地はありません。
    OSの機構を実装するのに内部定義ではないラッパー関数やマクロを持って来て使うのが適切かは、CCRXmachine.h/.cのあり方とは別に考えるべきだとも思います。ここではごっちゃに議論されている気がします。