GNU-RX 8.3.0 の最適化と倍精度浮動小数点オプション

Renesas GNU-RX 8.3.0 の最適化

Renesas GNU-RX の最適化は、通常の gcc (7.5.0) とは異なるようだー
より、深い最適化を行っている。

gcc-7.5.0 で、以下のプログラムをコンパイルすると・・

    typedef device::PORT<device::PORT0, device::bitpos::B1> LED;

    while(1) {
        utils::delay::milli_second(250);
        LED::P = 0;
        utils::delay::milli_second(250);
        LED::P = 1;
    }

論理演算を行ったコードが生成される。

ffc0029c:       cc 3e                           mov.b   [r3], r14
ffc0029e:       75 42 fa                        mov.l   #250, r2
ffc002a1:       75 2e fe                        and     #-2, r14
ffc002a4:       c3 3e                           mov.b   r14, [r3]

ffc002bc:       cc 3e                           mov.b   [r3], r14
ffc002be:       65 1e                           or      #1, r14
ffc002c0:       c3 3e                           mov.b   r14, [r3]

※中間に、「mov.l #250, r2」が挟まれてるのが多少痛いものの、まぁ普通だ。

Renesas GNU-RX では・・・

ffc00278:       f0 38                           bclr    #0, [r3].b

ffc00294:       f0 30                           bset    #0, [r3].b

ビット操作命令になっている。

RAYTRACE_sample が、361ms から 351ms に時間短縮したのも、他、細かい最適化によるものと思われる。
ルネサス社が魔改造したコンパイラは、高性能なのだと思われる。
※何故、gcc のオリジナルコードにマージしないのか?、疑問は残る・・・

Renesas GNU-RX 8.3.0 のオプション

倍精度浮動小数点命令を生成するには、コアが「RXv3」でなおかつ、「dfpu」を有効にすれば良いらしい。
※gcc のソースコードで、RX マイコンに関係する部分を少し読んでみた。

     -misa=v3 -mdfpu

なので、上記オプションを使って、簡単なコードで調べてみた。

    double a = 0.0;
    while(1) {
        utils::delay::milli_second(250);
        LED::P = 0;
        utils::delay::milli_second(250);
        LED::P = 1;
        a += 0.1;
        utils::format("%5.4f\n") % static_cast<float>(a);
    }

アセンブルリストを見てみると、確かに「倍精度浮動小数点命令」が生成されている、「a + 0.1;」の部分

ffc003d2:       fc c9 08 12 10                  dmov.D 72[r0], dr1
ffc003d7:       f9 03 00 9a 99 99 99            dmov.L #0x9999999a, drl0
ffc003de:       f9 03 02 99 99 b9 3f            dmov.L #0x3fb99999, drh0
ffc003e5:       76 90 00 11                     dadd  dr1, dr0, dr1
ffc003e9:       fc 79 08 12 10                  dmov.D dr1, 72[r0]

※ 64 ビットの IEEE-754 で定数 0.1 の表現は、0x3fb9'9999'9999'999a となる。
※ 64 ビットの定数をレジスターにロードするコストは大きい・・・

ちゃんと、倍精度の命令を生成しているので、RAYTRACE_sample を走らせてみた。

・・・逆に遅くなる。

調べると、dfpu を指定しない場合、常に32ビットで演算されていたものが、dfpu の指定で、部分的に64ビットの演算が行われる為のようだ。

実際にプログラムで利用する際は、細心の注意が必要だと思える・・・
※インテル CPU の場合、double を float にして計算すると、逆に遅くなるが、それとは対照的だ・・
でも、原理は理解は出来る。

それでも、64ビットの計算を、専用命令で行えるのは、ソフトエミュレーションに比べて格段に速いと思われるので、倍精度命令が生成される事実は心強い。

TFU についての調査

TFU については、仕様が公開されていないので、どのような物か、良く判らない・・・

gcc のソースコード「gcc/config/rx/rx.opt」を見ると・・・

EnumValue
Enum(rx_tfu_types) String(intrinsic) Value(RX_INTRINSIC)

EnumValue
Enum(rx_tfu_types) String(intrinsic,mathlib) Value(RX_MATHLIB)

とあるので、

    -mtfu=intrinsic

    -mtfu=intrinsic,mathlib

のどちらかを設定すれば良さそうだと判る。

「gcc/config/rx/rx.c」で、

    if (TARGET_TFU)
    {
      ADD_RX_TFU_BUILTIN (INIT, "__init_tfu", void);
      ADD_RX_BUILTIN3 (SINCOSF, "sincosf", void, float, float_ptr, float_ptr);
      ADD_RX_BUILTIN4 (ATAN2HYPOTF, "atan2hypotf", void, float, float, float_ptr, float_ptr);
      if (rx_tfu_type == RX_MATHLIB)
      {
        ADD_RX_BUILTIN1 (SINF, "sinf", float, float);
        ADD_RX_BUILTIN1 (COSF, "cosf", float, float);
        ADD_RX_BUILTIN2 (ATAN2F, "atan2f", float, float, float);
        ADD_RX_BUILTIN2 (HYPOTF, "hypotf", float, float, float);
      }
    }

となっている、
初期化の関数と思われる「__init_tfu」は、勝手に呼ぶコードが埋め込まれるのか不明だ。
※自動的に ctor に積まれるのかもしれない・・・

上記関数が演算器で演算されるものと思われるが、どのくらい効果があるのか不明・・・
また、現段階では、演算器が使われているかも不明で、何か、他に設定する事があるのかもとも思う。
とりあえず、TFU に関しては、調査を続ける。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください