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
  • こんにちは。NoMaYです。

    幾つか前の投稿で書いたCC-RXで積和演算を行うrmpab()関数(およびrmpaw()関数とrmpal()関数も)ですが、GNURXでの今回のCCRXmachine2.hの実装が何か汚くなって来たので、少し頭を冷やしてGoogle検索していたところ、GNURXのビルトイン関数に__builtin_rx_rmpa()という関数があることに気付きました。ところが、これがまた悩ましい仕様になっていました。

    void __builtin_rx_rmpa (void)

        Generates the rmpa machine instruction which initiates a repeated multiply and accumulate sequence.

    GNURX
    gcc-renesas.com/migration-guides/rx/index.html#Build_in

    GCC本家
    gcc.gnu.org/onlinedocs/gcc/RX-Built-in-Functions.html#index-_005f_005fbuiltin_005frx_005frmpa

    悩ましい点の1つ目は、積和演算関数は積和演算命令のデータのサイズ(B/W/L)に応じて3種類あるのですが、この__builtin_rx_rmpa()関数はバイトサイズ用のものであり、他のデータサイズ用のものが無い点です。

    2つ目は、積和演算関数には引数が4つあるのですが、この__builtin_rx_rmpa()関数には引数がありませんので、一体どうやって使えば良いのか分からない(ドキュメントに使い方の記述が無い)点です。加えて、恐らくこの様に使うに違いない、というのが分かっても試してみると、最適化無しでしか使えない点です。

    それで、まず使い方に関しては、RedHat社で組み込み向けGNUコンパイラを開発されているDJ Delorie氏が本家Rulzへ投稿したrmpa_gcc.zipのrmpa.cの以下のインラインアセンブラ部分をこの__builtin_rx_rmpa()関数で置き換える、ということになる筈だと思います。(ちなみに、今回のCCRXmachine2.hでも苦し紛れに同様な記述をしていたのですが、どうやらその記述で合っていそうだ、ということが分かって来ました。)

    Optimizing multiply-accumulate (RMPA) with GCC
    renesasrulz.com/rx/f/rx---forum/2509/optimizing-multiply-accumulate-rmpa-with-gcc


    rmpa.c (rmpa_gcc.zipに含まれているソース)

    #include "data.h"

    extern __inline__ __attribute__((always_inline))
    long long
    rmpaw (long long init, unsigned long count, short *a, short *b)
    {
      register long long rv __asm__("r4") = init;
      register unsigned long count_out __asm__("r3") = count;
      register short *a_out __asm__("r1") = a;
      register short *b_out __asm__("r2") = b;

      __asm__ volatile ("rmpa.w"
        : "=r" (rv), "=r" (count_out) , "=r" (a_out), "=r" (b_out)
        : "0" (rv), "1" (count_out), "2" (a_out), "3" (b_out)
        : "r6");
      return rv;
    }

    long long mac (short *a, short *b, int len)
    {
      return rmpaw (0, len, a, b);
    }

    これをそのままGNURX 2018q1でコンパイルした場合

    -O3
    ⇒ コードはソースの意図通り (もともと 引数 a --> r1, 引数 b --> r2, 引数 len --> r3 で呼ばれる)
    ⇒ ただし、そもそもソース上でr6を初期化しておらず、積和演算結果が意図通りにならない場合がある筈
    ⇒ また、アセンブラ記述部がa[0]~a[count-1]とb[0]~b[count-1]を参照しているという情報が無いので、
      上の例では意図通りのコードが生成されたものの、もっと複雑なソースにrmpaw()関数がインライン展開
      された場合に誤ったコードが生成される可能性がある(と思われます、、、詳細は後述します、、、)
       4                                    .global _mac
       6                                _mac:
      11 0000 7E A6                         push.l  r6
      17 0002 66 04                         mov.L   #0, r4
      18 0004 EF 45                         mov.L   r4, r5
      21 0006 7F 8D                         rmpa.w
      27 0008 EF 41                         mov.L   r4, r1
      28 000a EF 52                         mov.L   r5, r2
      29 000c 3F 66 01                      rtsd    #4, r6-r6
    -O0
    ⇒ コンパイルエラーになってしまう
    >make
    rx-elf-gcc -g -O0 -MMD -Wa,-adln=rmpa.lst   -c -o rmpa.o rmpa.c
    rmpa.c: In function 'mac':
    rmpa.c:22:1: error: r6 cannot be used in asm here
     }
     ^

    ところが、以下の通りインラインアセンブラ部分をこの__builtin_rx_rmpa()関数で置き換えてコンパイルしてみると、最適化有りでは正しくないコードが生成されてしまっている、ということに気付きます、、、

      register long long rv __asm__("r4") = init;
      register unsigned long count_out __asm__("r3") = count;
      register short *a_out __asm__("r1") = a;
      register short *b_out __asm__("r2") = b;

      __builtin_rx_rmpa();
      return rv;

    GNURX 2018q1でコンパイルした場合

    -O3 / -O2 / -O1
    ⇒ コードが滅茶苦茶 (r5:r4にinitの初期値0が設定されておらず、逆に戻り値はinitの初期値0のまま)
    ⇒ 補足すれば、最適化処理で__builtin_rx_rmpa();は入出力の全く無いNOP命令と同じ扱い!をされている
       4                                    .global _mac
       6                                _mac:
      11 0000 6E 67                         pushm   r6-r7
      13 0002 EF 06                         mov.L   r0, r6
      19 0004 7F 8E                         rmpa
      24 0006 66 01                         mov.L   #0, r1
      25 0008 EF 12                         mov.L   r1, r2
      26 000a 3F 67 02                      rtsd    #8, r6-r7
    -O0
    ⇒ コードはソースの意図通り
       4                                    .global _mac
       6                                _mac:
      10 0000 7E A6                         push.l  r6
      12 0002 71 06 E0                      add #-32, r0, r6
      14 0005 EF 60                         mov.L   r6, r0
      16 0007 A1 69                         mov.L   r1, 20[r6]      引数 a
      17 0009 A1 E2                         mov.L   r2, 24[r6]      引数 b
      18 000b A1 EB                         mov.L   r3, 28[r6]      引数 c
      20 000d A9 ED                         mov.L   28[r6], r5
      21 000f F8 66 00                      mov.L   #0, [r6]        0 --> init(下位32ビット)
      22 0012 3E 61 00                      mov.L   #0, 4[r6]       0 --> init(上位32ビット)
      23 0015 A0 E5                         mov.L   r5, 8[r6]       引数 c --> r5 --> count
      24 0017 A9 6D                         mov.L   20[r6], r5
      25 0019 A0 ED                         mov.L   r5, 12[r6]      引数 a --> r5 --> a_out
      26 001b A9 E5                         mov.L   24[r6], r5
      27 001d A1 65                         mov.L   r5, 16[r6]      引数 b --> r5 --> b_out
      31 001f EC 64                         mov.L   [r6], r4        init(下位32ビット) --> r4
      32 0021 A8 6D                         mov.L   4[r6], r5       init(上位32ビット) --> r5
      34 0023 A8 E3                         mov.L   8[r6], r3       count --> r3
      36 0025 A8 E9                         mov.L   12[r6], r1      a_out --> r1
      38 0027 A9 62                         mov.L   16[r6], r2      b_out --> r2
      40 0029 7F 8E                         rmpa
      42 002b EF 42                         mov.L   r4, r2
      43 002d EF 53                         mov.L   r5, r3
      44 002f EF 24                         mov.L   r2, r4
      45 0031 EF 35                         mov.L   r3, r5
      49 0033 EF 42                         mov.L   r4, r2
      50 0035 EF 53                         mov.L   r5, r3
      51 0037 EF 24                         mov.L   r2, r4
      52 0039 EF 35                         mov.L   r3, r5
      54 003b EF 41                         mov.L   r4, r1          r4 --> 戻り値(下位32ビット)
      55 003d EF 52                         mov.L   r5, r2          r5 --> 戻り値(上位32ビット)
      56 003f 3F 66 09                      rtsd    #36, r6-r6

    このような具合であり、以前に投稿した__builtin_rx_xchg()関数で「複雑難解な最適化処理との兼ね合いでどちらに転ぶか分からない不安があって悩ましい」と感じたのと同様に、この__builtin_rx_rmpa()関数でも最適化処理との絡みが悩ましい、と感じました。

    そして、最適化処理との絡みという点で、DJ Delorie氏のインラインアセンブラ部分も怪しい気がします。実は、今回のCCRXmachine2.hの為に色々調べていたので気付いたのですが、ストリング操作命令では以下のような記述が必要であり、それはRMPA命令でも同じだと思われます。ところが、DJ Delorie氏のインラインアセンブラ部分に、それに相当する記述(アセンブラ記述部がa[0]~a[count-1]とb[0]~b[count-1]を参照しているという記述)がありませんので、複雑なソースにrmpaw()関数がインライン展開された場合に最適化処理により誤ったコードが生成される可能性があると思われます、、、

    6.45.2 Extended Asm - Assembler Instructions with C Expression Operands
    gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Clobbers-and-Scratch-Registers


    IA-32インテル®アーキテクチャ ソフトウェア・デベロッパーズ・マニュアル 中巻B:命令セット・リファレンスN-Z
    www.intel.com/content/dam/www/public/ijkk/jp/ja/documents/developer/IA32_Arh_Dev_Man_Vol2B_i.pdf


    そもそも、DJ Delorie氏のソース上でr6が初期化されていませんので、積和演算結果が意図通りにならない場合がある筈だと思われます、、、

    RXファミリ ユーザーズマニュアル ソフトウェア編
    www.renesas.com/ja-jp/doc/products/mpumcu/doc/rx_family/r01us0032jj0120_rxsm.pdf


    ちなみに、今回のCCRXmachine2.hの手元の作業中のソースでは、rmpab()関数(およびrmpaw()関数とrmpal()関数も)は、ようやく以下の記述に至ったところです。

    #ifndef rmpab
    #define rmpab(init, count, addr1, addr2) ccrx_machine_h_rmpab(init, count, addr1, addr2)
    #endif
    static __inline__ long long ccrx_machine_h_rmpab(long long init, unsigned long count, signed char *addr1, signed char *addr2) __attribute__((always_inline));
    static __inline__ long long ccrx_machine_h_rmpab(long long init, unsigned long count, signed char *addr1, signed char *addr2)
    {
    /* CC-RX V2.03
            ARG init = R2:R1
            ARG count = R3
            ARG addr1 = R4
            ARG addr2 = 04H[R0](08H[R0] after push R6)
            RET R2:R1

            PUSH.L R6
            MOV.L R1, R14
            MOV.L R2, R5
            MOV.L 08H[R0], R2
            SHAR #1FH, R5, R6
            MOV.L R4, R1
            MOV.L R14, R4
            RMPA.B
            MOV.L R5, R2
            MOV.L R4, R1
            RTSD #04H, R6-R6
    */
        register long long _r5r4 __asm__("r4") = init;
        register signed char *_r1 __asm__("r1") = addr1;
        register signed char *_r2 __asm__("r2") = addr2;
        register unsigned long _r3 __asm__("r3") = count;
    #ifdef __OPTIMIZE__
        /* In case of other than -O0, we assign r6. */
        register signed long _rS __asm__("r6") = (signed long)(init >> 63);
    #else
        /* In case of -O0, we assign r8 because r6 and r7 are reserved for the frame pointer and something. */
        register signed long _rS __asm__("r8") = (signed long)(init >> 63);
    #endif
        __asm__ volatile
        (
            /* AssemblerTemplate */
    #ifdef __OPTIMIZE__
            "RMPA.B"        "\n\t"
    #else
            "XCHG R6, R8"   "\n\t"
            "RMPA.B"        "\n\t"
            "XCHG R6, R8"   "\n\t"
    #endif
            : /* OutputOperands */
                /**/ "+r" (_rS),
                /**/ "+r" (_r5r4),
                /**/ "+r" (_r3)
            : /* InputOperands */
                /**/ "r" (_r1),
                /**/ "r" (_r2),
                /**/ "m" (*(signed char (*)[count]) addr1),
                /**/ "m" (*(signed char (*)[count]) addr2)
            : /* Clobbers */
                /*"r1",*/ /* This causes a compile error: asm-specifier for variable '_r1' conflicts with asm clobber list */
                /*"r2" */ /* This causes a compile error: asm-specifier for variable '_r2' conflicts with asm clobber list */
        );
        __asm__ volatile
        (
            /* AssemblerTemplate */
            ""/*"NOP"*/     "\n\t"
            : /* OutputOperands */
                /* No outputs. */
            : /* InputOperands */
                /* No inputs. */
            : /* Clobbers */
                "r1",
                "r2"
            /* This asm statement can make the compiler to recognize that r1 and r2 are not equivalent to addr1 and addr2. */
            /* For example, after replacing 'return _r5r4;' --> 'return *addr1 * *addr2;' tentatively, code are different. */
    /* GNURX 2018q1 -O2
    In case of WITHOUT this asm statement, it is recognized that r1 and r2 are equivalent to addr1 and addr2 mistakenly.
         0019 7E A6                         push.l  r6
         001b 60 40                         sub     #4, r0
         001d EF 25                         mov.L   r2, r5
         001f A8 8A                         mov.L   12[r0], r2
         0021 FC 43 41                      xchg    r4, r1
         0024 FD BF 56                      shar    #31, r5, r6
         0027 7F 8C                         RMPA.B
     return *addr1 * *addr2;
         0029 CC 15                         mov.B   [r1], r5
         002b CC 21                         mov.B   [r2], r1
         002d 4F 51                         mul     r5, r1
         002f FD BF 12                      shar    #31, r1, r2
         0032 3F 66 02                      rtsd    #8, r6-r6
    In case of WITH this asm statement, it is recognized that r1 and r2 are not equivalent to addr1 and addr2 correctly.
         0019 7E A6                         push.l  r6
         001b 60 40                         sub     #4, r0
         001d EF 25                         mov.L   r2, r5
         001f ED 0E 03                      mov.L   12[r0], r14
         0022 EF 4F                         mov.L   r4, r15
         0024 EF 14                         mov.L   r1, r4
         0026 EF E2                         mov.L   r14, r2
         0028 EF F1                         mov.L   r15, r1
         002a FD BF 56                      shar    #31, r5, r6
         002d 7F 8C                         RMPA.B
     return *addr1 * *addr2;
         002f CC F1                         mov.B   [r15], r1
         0031 06 0C E1                      mul     [r14].B, r1
         0034 FD BF 12                      shar    #31, r1, r2
         0037 3F 66 02                      rtsd    #8, r6-r6
    */
        );
        return _r5r4;
    /* GNURX 2018q1 -O2
     108 0019 7E A6                         push.l  r6
     110 001b 60 40                         sub     #4, r0
     113 001d EF 25                         mov.L   r2, r5
     115 001f A8 8A                         mov.L   12[r0], r2
     120 0021 FC 43 41                      xchg    r4, r1
     122 0024 FD BF 56                      shar    #31, r5, r6
     125 0027 7F 8C                         RMPA.B
     134 0029 EF 41                         mov.L   r4, r1
     135 002b EF 52                         mov.L   r5, r2
     136 002d 3F 66 02                      rtsd    #8, r6-r6
    */
    /* GNURX 2018q1 -O0, (This caller is not good example, to be reconsidered...)
     185 00ab 6E 6C                         pushm   r6-r12
     187 00ad 71 06 D8                      add     #-40, r0, r6
     189 00b0 EF 60                         mov.L   r6, r0
     191 00b2 75 45 48                      mov.L   #0x48, r5
     192 00b5 4B 65                         add     r6, r5
     193 00b7 A1 69                         mov.L   r1, 20[r6]
     194 00b9 A1 E2                         mov.L   r2, 24[r6]
     195 00bb A1 EB                         mov.L   r3, 28[r6]
     196 00bd A2 64                         mov.L   r4, 32[r6]
     197 00bf A9 6C                         mov.L   20[r6], r4
     198 00c1 E3 64                         mov.L   r4, [r6]
     199 00c3 A9 E4                         mov.L   24[r6], r4
     200 00c5 A0 6C                         mov.L   r4, 4[r6]
     201 00c7 A9 EC                         mov.L   28[r6], r4
     202 00c9 A0 E4                         mov.L   r4, 8[r6]
     203 00cb AA 64                         mov.L   32[r6], r4
     204 00cd A0 EC                         mov.L   r4, 12[r6]
     205 00cf EC 55                         mov.L   [r5], r5
     206 00d1 A1 65                         mov.L   r5, 16[r6]
     210 00d3 EC 64                         mov.L   [r6], r4
     211 00d5 A8 6D                         mov.L   4[r6], r5
     213 00d7 A8 E9                         mov.L   12[r6], r1
     215 00d9 A9 62                         mov.L   16[r6], r2
     217 00db A8 E3                         mov.L   8[r6], r3
     219 00dd ED 6C 01                      mov.L   4[r6], r12
     220 00e0 FD BF CA                      shar    #31, r12, r10
     221 00e3 ED 6C 01                      mov.L   4[r6], r12
     222 00e6 FD BF CB                      shar    #31, r12, r11
     223 00e9 EF A8                         mov.L   r10, r8
     225 00eb ED 6A 03                      mov.L   12[r6], r10
     226 00ee ED 6B 04                      mov.L   16[r6], r11
     228 00f1 FC 43 68                      XCHG R6, R8
     229 00f4 7F 8C                         RMPA.B
     230 00f6 FC 43 68                      XCHG R6, R8
     239 00f9 EF 42                         mov.L   r4, r2
     240 00fb EF 53                         mov.L   r5, r3
     241 00fd EF 24                         mov.L   r2, r4
     242 00ff EF 35                         mov.L   r3, r5
     246 0101 EF 42                         mov.L   r4, r2
     247 0103 EF 53                         mov.L   r5, r3
     248 0105 EF 24                         mov.L   r2, r4
     249 0107 EF 35                         mov.L   r3, r5
     250 0109 EF 41                         mov.L   r4, r1
     251 010b EF 52                         mov.L   r5, r2
     252 010d 3F 6C 11                      rtsd    #68, r6-r12
    */
    }

     

Reply
  • こんにちは。NoMaYです。

    幾つか前の投稿で書いたCC-RXで積和演算を行うrmpab()関数(およびrmpaw()関数とrmpal()関数も)ですが、GNURXでの今回のCCRXmachine2.hの実装が何か汚くなって来たので、少し頭を冷やしてGoogle検索していたところ、GNURXのビルトイン関数に__builtin_rx_rmpa()という関数があることに気付きました。ところが、これがまた悩ましい仕様になっていました。

    void __builtin_rx_rmpa (void)

        Generates the rmpa machine instruction which initiates a repeated multiply and accumulate sequence.

    GNURX
    gcc-renesas.com/migration-guides/rx/index.html#Build_in

    GCC本家
    gcc.gnu.org/onlinedocs/gcc/RX-Built-in-Functions.html#index-_005f_005fbuiltin_005frx_005frmpa

    悩ましい点の1つ目は、積和演算関数は積和演算命令のデータのサイズ(B/W/L)に応じて3種類あるのですが、この__builtin_rx_rmpa()関数はバイトサイズ用のものであり、他のデータサイズ用のものが無い点です。

    2つ目は、積和演算関数には引数が4つあるのですが、この__builtin_rx_rmpa()関数には引数がありませんので、一体どうやって使えば良いのか分からない(ドキュメントに使い方の記述が無い)点です。加えて、恐らくこの様に使うに違いない、というのが分かっても試してみると、最適化無しでしか使えない点です。

    それで、まず使い方に関しては、RedHat社で組み込み向けGNUコンパイラを開発されているDJ Delorie氏が本家Rulzへ投稿したrmpa_gcc.zipのrmpa.cの以下のインラインアセンブラ部分をこの__builtin_rx_rmpa()関数で置き換える、ということになる筈だと思います。(ちなみに、今回のCCRXmachine2.hでも苦し紛れに同様な記述をしていたのですが、どうやらその記述で合っていそうだ、ということが分かって来ました。)

    Optimizing multiply-accumulate (RMPA) with GCC
    renesasrulz.com/rx/f/rx---forum/2509/optimizing-multiply-accumulate-rmpa-with-gcc


    rmpa.c (rmpa_gcc.zipに含まれているソース)

    #include "data.h"

    extern __inline__ __attribute__((always_inline))
    long long
    rmpaw (long long init, unsigned long count, short *a, short *b)
    {
      register long long rv __asm__("r4") = init;
      register unsigned long count_out __asm__("r3") = count;
      register short *a_out __asm__("r1") = a;
      register short *b_out __asm__("r2") = b;

      __asm__ volatile ("rmpa.w"
        : "=r" (rv), "=r" (count_out) , "=r" (a_out), "=r" (b_out)
        : "0" (rv), "1" (count_out), "2" (a_out), "3" (b_out)
        : "r6");
      return rv;
    }

    long long mac (short *a, short *b, int len)
    {
      return rmpaw (0, len, a, b);
    }

    これをそのままGNURX 2018q1でコンパイルした場合

    -O3
    ⇒ コードはソースの意図通り (もともと 引数 a --> r1, 引数 b --> r2, 引数 len --> r3 で呼ばれる)
    ⇒ ただし、そもそもソース上でr6を初期化しておらず、積和演算結果が意図通りにならない場合がある筈
    ⇒ また、アセンブラ記述部がa[0]~a[count-1]とb[0]~b[count-1]を参照しているという情報が無いので、
      上の例では意図通りのコードが生成されたものの、もっと複雑なソースにrmpaw()関数がインライン展開
      された場合に誤ったコードが生成される可能性がある(と思われます、、、詳細は後述します、、、)
       4                                    .global _mac
       6                                _mac:
      11 0000 7E A6                         push.l  r6
      17 0002 66 04                         mov.L   #0, r4
      18 0004 EF 45                         mov.L   r4, r5
      21 0006 7F 8D                         rmpa.w
      27 0008 EF 41                         mov.L   r4, r1
      28 000a EF 52                         mov.L   r5, r2
      29 000c 3F 66 01                      rtsd    #4, r6-r6
    -O0
    ⇒ コンパイルエラーになってしまう
    >make
    rx-elf-gcc -g -O0 -MMD -Wa,-adln=rmpa.lst   -c -o rmpa.o rmpa.c
    rmpa.c: In function 'mac':
    rmpa.c:22:1: error: r6 cannot be used in asm here
     }
     ^

    ところが、以下の通りインラインアセンブラ部分をこの__builtin_rx_rmpa()関数で置き換えてコンパイルしてみると、最適化有りでは正しくないコードが生成されてしまっている、ということに気付きます、、、

      register long long rv __asm__("r4") = init;
      register unsigned long count_out __asm__("r3") = count;
      register short *a_out __asm__("r1") = a;
      register short *b_out __asm__("r2") = b;

      __builtin_rx_rmpa();
      return rv;

    GNURX 2018q1でコンパイルした場合

    -O3 / -O2 / -O1
    ⇒ コードが滅茶苦茶 (r5:r4にinitの初期値0が設定されておらず、逆に戻り値はinitの初期値0のまま)
    ⇒ 補足すれば、最適化処理で__builtin_rx_rmpa();は入出力の全く無いNOP命令と同じ扱い!をされている
       4                                    .global _mac
       6                                _mac:
      11 0000 6E 67                         pushm   r6-r7
      13 0002 EF 06                         mov.L   r0, r6
      19 0004 7F 8E                         rmpa
      24 0006 66 01                         mov.L   #0, r1
      25 0008 EF 12                         mov.L   r1, r2
      26 000a 3F 67 02                      rtsd    #8, r6-r7
    -O0
    ⇒ コードはソースの意図通り
       4                                    .global _mac
       6                                _mac:
      10 0000 7E A6                         push.l  r6
      12 0002 71 06 E0                      add #-32, r0, r6
      14 0005 EF 60                         mov.L   r6, r0
      16 0007 A1 69                         mov.L   r1, 20[r6]      引数 a
      17 0009 A1 E2                         mov.L   r2, 24[r6]      引数 b
      18 000b A1 EB                         mov.L   r3, 28[r6]      引数 c
      20 000d A9 ED                         mov.L   28[r6], r5
      21 000f F8 66 00                      mov.L   #0, [r6]        0 --> init(下位32ビット)
      22 0012 3E 61 00                      mov.L   #0, 4[r6]       0 --> init(上位32ビット)
      23 0015 A0 E5                         mov.L   r5, 8[r6]       引数 c --> r5 --> count
      24 0017 A9 6D                         mov.L   20[r6], r5
      25 0019 A0 ED                         mov.L   r5, 12[r6]      引数 a --> r5 --> a_out
      26 001b A9 E5                         mov.L   24[r6], r5
      27 001d A1 65                         mov.L   r5, 16[r6]      引数 b --> r5 --> b_out
      31 001f EC 64                         mov.L   [r6], r4        init(下位32ビット) --> r4
      32 0021 A8 6D                         mov.L   4[r6], r5       init(上位32ビット) --> r5
      34 0023 A8 E3                         mov.L   8[r6], r3       count --> r3
      36 0025 A8 E9                         mov.L   12[r6], r1      a_out --> r1
      38 0027 A9 62                         mov.L   16[r6], r2      b_out --> r2
      40 0029 7F 8E                         rmpa
      42 002b EF 42                         mov.L   r4, r2
      43 002d EF 53                         mov.L   r5, r3
      44 002f EF 24                         mov.L   r2, r4
      45 0031 EF 35                         mov.L   r3, r5
      49 0033 EF 42                         mov.L   r4, r2
      50 0035 EF 53                         mov.L   r5, r3
      51 0037 EF 24                         mov.L   r2, r4
      52 0039 EF 35                         mov.L   r3, r5
      54 003b EF 41                         mov.L   r4, r1          r4 --> 戻り値(下位32ビット)
      55 003d EF 52                         mov.L   r5, r2          r5 --> 戻り値(上位32ビット)
      56 003f 3F 66 09                      rtsd    #36, r6-r6

    このような具合であり、以前に投稿した__builtin_rx_xchg()関数で「複雑難解な最適化処理との兼ね合いでどちらに転ぶか分からない不安があって悩ましい」と感じたのと同様に、この__builtin_rx_rmpa()関数でも最適化処理との絡みが悩ましい、と感じました。

    そして、最適化処理との絡みという点で、DJ Delorie氏のインラインアセンブラ部分も怪しい気がします。実は、今回のCCRXmachine2.hの為に色々調べていたので気付いたのですが、ストリング操作命令では以下のような記述が必要であり、それはRMPA命令でも同じだと思われます。ところが、DJ Delorie氏のインラインアセンブラ部分に、それに相当する記述(アセンブラ記述部がa[0]~a[count-1]とb[0]~b[count-1]を参照しているという記述)がありませんので、複雑なソースにrmpaw()関数がインライン展開された場合に最適化処理により誤ったコードが生成される可能性があると思われます、、、

    6.45.2 Extended Asm - Assembler Instructions with C Expression Operands
    gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Clobbers-and-Scratch-Registers


    IA-32インテル®アーキテクチャ ソフトウェア・デベロッパーズ・マニュアル 中巻B:命令セット・リファレンスN-Z
    www.intel.com/content/dam/www/public/ijkk/jp/ja/documents/developer/IA32_Arh_Dev_Man_Vol2B_i.pdf


    そもそも、DJ Delorie氏のソース上でr6が初期化されていませんので、積和演算結果が意図通りにならない場合がある筈だと思われます、、、

    RXファミリ ユーザーズマニュアル ソフトウェア編
    www.renesas.com/ja-jp/doc/products/mpumcu/doc/rx_family/r01us0032jj0120_rxsm.pdf


    ちなみに、今回のCCRXmachine2.hの手元の作業中のソースでは、rmpab()関数(およびrmpaw()関数とrmpal()関数も)は、ようやく以下の記述に至ったところです。

    #ifndef rmpab
    #define rmpab(init, count, addr1, addr2) ccrx_machine_h_rmpab(init, count, addr1, addr2)
    #endif
    static __inline__ long long ccrx_machine_h_rmpab(long long init, unsigned long count, signed char *addr1, signed char *addr2) __attribute__((always_inline));
    static __inline__ long long ccrx_machine_h_rmpab(long long init, unsigned long count, signed char *addr1, signed char *addr2)
    {
    /* CC-RX V2.03
            ARG init = R2:R1
            ARG count = R3
            ARG addr1 = R4
            ARG addr2 = 04H[R0](08H[R0] after push R6)
            RET R2:R1

            PUSH.L R6
            MOV.L R1, R14
            MOV.L R2, R5
            MOV.L 08H[R0], R2
            SHAR #1FH, R5, R6
            MOV.L R4, R1
            MOV.L R14, R4
            RMPA.B
            MOV.L R5, R2
            MOV.L R4, R1
            RTSD #04H, R6-R6
    */
        register long long _r5r4 __asm__("r4") = init;
        register signed char *_r1 __asm__("r1") = addr1;
        register signed char *_r2 __asm__("r2") = addr2;
        register unsigned long _r3 __asm__("r3") = count;
    #ifdef __OPTIMIZE__
        /* In case of other than -O0, we assign r6. */
        register signed long _rS __asm__("r6") = (signed long)(init >> 63);
    #else
        /* In case of -O0, we assign r8 because r6 and r7 are reserved for the frame pointer and something. */
        register signed long _rS __asm__("r8") = (signed long)(init >> 63);
    #endif
        __asm__ volatile
        (
            /* AssemblerTemplate */
    #ifdef __OPTIMIZE__
            "RMPA.B"        "\n\t"
    #else
            "XCHG R6, R8"   "\n\t"
            "RMPA.B"        "\n\t"
            "XCHG R6, R8"   "\n\t"
    #endif
            : /* OutputOperands */
                /**/ "+r" (_rS),
                /**/ "+r" (_r5r4),
                /**/ "+r" (_r3)
            : /* InputOperands */
                /**/ "r" (_r1),
                /**/ "r" (_r2),
                /**/ "m" (*(signed char (*)[count]) addr1),
                /**/ "m" (*(signed char (*)[count]) addr2)
            : /* Clobbers */
                /*"r1",*/ /* This causes a compile error: asm-specifier for variable '_r1' conflicts with asm clobber list */
                /*"r2" */ /* This causes a compile error: asm-specifier for variable '_r2' conflicts with asm clobber list */
        );
        __asm__ volatile
        (
            /* AssemblerTemplate */
            ""/*"NOP"*/     "\n\t"
            : /* OutputOperands */
                /* No outputs. */
            : /* InputOperands */
                /* No inputs. */
            : /* Clobbers */
                "r1",
                "r2"
            /* This asm statement can make the compiler to recognize that r1 and r2 are not equivalent to addr1 and addr2. */
            /* For example, after replacing 'return _r5r4;' --> 'return *addr1 * *addr2;' tentatively, code are different. */
    /* GNURX 2018q1 -O2
    In case of WITHOUT this asm statement, it is recognized that r1 and r2 are equivalent to addr1 and addr2 mistakenly.
         0019 7E A6                         push.l  r6
         001b 60 40                         sub     #4, r0
         001d EF 25                         mov.L   r2, r5
         001f A8 8A                         mov.L   12[r0], r2
         0021 FC 43 41                      xchg    r4, r1
         0024 FD BF 56                      shar    #31, r5, r6
         0027 7F 8C                         RMPA.B
     return *addr1 * *addr2;
         0029 CC 15                         mov.B   [r1], r5
         002b CC 21                         mov.B   [r2], r1
         002d 4F 51                         mul     r5, r1
         002f FD BF 12                      shar    #31, r1, r2
         0032 3F 66 02                      rtsd    #8, r6-r6
    In case of WITH this asm statement, it is recognized that r1 and r2 are not equivalent to addr1 and addr2 correctly.
         0019 7E A6                         push.l  r6
         001b 60 40                         sub     #4, r0
         001d EF 25                         mov.L   r2, r5
         001f ED 0E 03                      mov.L   12[r0], r14
         0022 EF 4F                         mov.L   r4, r15
         0024 EF 14                         mov.L   r1, r4
         0026 EF E2                         mov.L   r14, r2
         0028 EF F1                         mov.L   r15, r1
         002a FD BF 56                      shar    #31, r5, r6
         002d 7F 8C                         RMPA.B
     return *addr1 * *addr2;
         002f CC F1                         mov.B   [r15], r1
         0031 06 0C E1                      mul     [r14].B, r1
         0034 FD BF 12                      shar    #31, r1, r2
         0037 3F 66 02                      rtsd    #8, r6-r6
    */
        );
        return _r5r4;
    /* GNURX 2018q1 -O2
     108 0019 7E A6                         push.l  r6
     110 001b 60 40                         sub     #4, r0
     113 001d EF 25                         mov.L   r2, r5
     115 001f A8 8A                         mov.L   12[r0], r2
     120 0021 FC 43 41                      xchg    r4, r1
     122 0024 FD BF 56                      shar    #31, r5, r6
     125 0027 7F 8C                         RMPA.B
     134 0029 EF 41                         mov.L   r4, r1
     135 002b EF 52                         mov.L   r5, r2
     136 002d 3F 66 02                      rtsd    #8, r6-r6
    */
    /* GNURX 2018q1 -O0, (This caller is not good example, to be reconsidered...)
     185 00ab 6E 6C                         pushm   r6-r12
     187 00ad 71 06 D8                      add     #-40, r0, r6
     189 00b0 EF 60                         mov.L   r6, r0
     191 00b2 75 45 48                      mov.L   #0x48, r5
     192 00b5 4B 65                         add     r6, r5
     193 00b7 A1 69                         mov.L   r1, 20[r6]
     194 00b9 A1 E2                         mov.L   r2, 24[r6]
     195 00bb A1 EB                         mov.L   r3, 28[r6]
     196 00bd A2 64                         mov.L   r4, 32[r6]
     197 00bf A9 6C                         mov.L   20[r6], r4
     198 00c1 E3 64                         mov.L   r4, [r6]
     199 00c3 A9 E4                         mov.L   24[r6], r4
     200 00c5 A0 6C                         mov.L   r4, 4[r6]
     201 00c7 A9 EC                         mov.L   28[r6], r4
     202 00c9 A0 E4                         mov.L   r4, 8[r6]
     203 00cb AA 64                         mov.L   32[r6], r4
     204 00cd A0 EC                         mov.L   r4, 12[r6]
     205 00cf EC 55                         mov.L   [r5], r5
     206 00d1 A1 65                         mov.L   r5, 16[r6]
     210 00d3 EC 64                         mov.L   [r6], r4
     211 00d5 A8 6D                         mov.L   4[r6], r5
     213 00d7 A8 E9                         mov.L   12[r6], r1
     215 00d9 A9 62                         mov.L   16[r6], r2
     217 00db A8 E3                         mov.L   8[r6], r3
     219 00dd ED 6C 01                      mov.L   4[r6], r12
     220 00e0 FD BF CA                      shar    #31, r12, r10
     221 00e3 ED 6C 01                      mov.L   4[r6], r12
     222 00e6 FD BF CB                      shar    #31, r12, r11
     223 00e9 EF A8                         mov.L   r10, r8
     225 00eb ED 6A 03                      mov.L   12[r6], r10
     226 00ee ED 6B 04                      mov.L   16[r6], r11
     228 00f1 FC 43 68                      XCHG R6, R8
     229 00f4 7F 8C                         RMPA.B
     230 00f6 FC 43 68                      XCHG R6, R8
     239 00f9 EF 42                         mov.L   r4, r2
     240 00fb EF 53                         mov.L   r5, r3
     241 00fd EF 24                         mov.L   r2, r4
     242 00ff EF 35                         mov.L   r3, r5
     246 0101 EF 42                         mov.L   r4, r2
     247 0103 EF 53                         mov.L   r5, r3
     248 0105 EF 24                         mov.L   r2, r4
     249 0107 EF 35                         mov.L   r3, r5
     250 0109 EF 41                         mov.L   r4, r1
     251 010b EF 52                         mov.L   r5, r2
     252 010d 3F 6C 11                      rtsd    #68, r6-r12
    */
    }

     

Children
No Data