RL78のローカル変数のメモリアドレスについて

こんにちは。SUZUKIです。

 

RL78/G14用のプログラムをCS+で開発中に良く分からない現象に遭遇しました。

プログラムは

void test(char a){

char b = 0;

b = a+10;

}

という簡単なものです。

この時に変数a,bをウォッチするとアドレスがそれぞれ[L:REG][H:REG]となっており、変数bの値は0のままでした。

動作する条件としては下記3つありました。

1.変数bの宣言をグローバルで行った場合

2.別の変数(使用しない)を関数内で宣言した場合

3.変数bの型をint型にした場合

これらの時は変数a,b共にアドレスが割り当てられ正常に動作しました。

これはどのような事が起きているのでしょうか。

宜しくお願い致します。

Parents
  • SUZUKIさん、こんにちは。NoMaYです。

    今回の件、アセンブラコードが全く分からなくても、わわいさんがアドバイスしているような、最適化のため変数への値の代入がなされなかった、ということの雰囲気が分かるような説明を考えてみました。今回の件はCC78K0Rだったのですが、インパクトが強そうな気がしましたので、説明としてはCC-RLを使うことにしました。

    まず、SUZUKIさんが書かれたコードはもともと以下のものでした。

    void test(char a){
        char b = 0;
        b = a+10;
        R_DAC0_Set_ConversionValue(b);
    }

    でも、よくよく考えると、b = 0 としたすぐ後に b = a+10 としていますので、プログラムの機能としては b = 0 は無くても良く、以下のコードで置き換えることが出来ます。

    void test(char a){
        char b;
        b = a+10;
        R_DAC0_Set_ConversionValue(b);
    }

    そうして、コードの置き換えを考え始めると、わざわざ a+10 を b に代入しなくても、以下のコードで置き換えることが出来ることに気付きます。

    void test(char a){
        R_DAC0_Set_ConversionValue(a+10);
    }

    ところで、敢えて置き換える価値はありませんが、下のように置き換えてもプログラムの機能としてはもともとのコードと等価です。ただ、この置き換えから、今回の件でウォッチで見た時に b = a+10 が実行されていないように見えた原因が何となく分かるのではないかと、思います。(人間が見れば b = 0 がプログラムの機能として意味が無いことは直ぐに分かりますが、コンパイラとしては少なくとも「a+10 を b に代入した後にその b を読み出して引数にセットする」という冗長な処理が無くなったので価値はある、だから置き換える、と判断することもあるということです。)

    void test(char a){
        char b = 0;
        R_DAC0_Set_ConversionValue(a+10);
    }

    ちなみに、CC-RLのデフォルトの最適化では、上の4つのコードは全て以下の同じアセンブラコードにコンパイルされました。(アセンブラコードの意味が分からなくても同じコードが生成されていることが伝われば良いかな、と考えました。) ソースは違うが、プログラムの機能としては同じなので、同じアセンブラコードになる、という訳です。

    00000009                      120  _test:
    00000009                      114       .STACK _test = 4
    00000009                      126       ;***       84 : void test(char a){
    00000009 0C0A                 128       add a, #0x0A
    0000000B                      129       ;***       85 :    char b = 0;
    0000000B                      130       ;***       86 :     b = a+10;
    0000000B                      131       ;***       87 :     R_DAC0_Set_ConversionValue(b);
    0000000B EC000000             133       br !!_R_DAC0_Set_ConversionValue
    0000000F                      134       ;***       88 : }
    00000009                      113  _test:
    00000009                      114       .STACK _test = 4
    00000009                      119       ;***       84 : void test(char a){
    00000009 0C0A                 121       add a, #0x0A
    0000000B                      122       ;***       85 :     char b;
    0000000B                      123       ;***       86 :     b = a+10;
    0000000B                      124       ;***       87 :     R_DAC0_Set_ConversionValue(b);
    0000000B EC000000             126       br !!_R_DAC0_Set_ConversionValue
    0000000F                      127       ;***       88 : }
    00000009                      113  _test:
    00000009                      114       .STACK _test = 4
    00000009                      119       ;***       84 : void test(char a){
    00000009 0C0A                 121       add a, #0x0A
    0000000B                      122       ;***       85 :     R_DAC0_Set_ConversionValue(a+10);
    0000000B EC000000             124       br !!_R_DAC0_Set_ConversionValue
    0000000F                      125       ;***       86 : }
    00000009                      113  _test:
    00000009                      114       .STACK _test = 4
    00000009                      119       ;***       84 : void test(char a){
    00000009 0C0A                 121       add a, #0x0A
    0000000B                      122       ;***       85 :     char b = 0;
    0000000B                      123       ;***       86 :     R_DAC0_Set_ConversionValue(a+10);
    0000000B EC000000             125       br !!_R_DAC0_Set_ConversionValue
    0000000F                      126       ;***       87 : }

    あと、プログラムの機能という点では、上のCC-RLのデフォルトの最適化ありでコンパイルしたアセンブラコードと、CC-RLで最適化無しでコンパイルした以下のアセンブラコードは、なんと等価ということになるのです。(アセンブラコードの意味が分からなくても量も内容も全然違うコードが生成されていることが伝われば良いかな、と考えました。)

    00000009                      121  _test:
    00000009                      122       .STACK _test = 6
    00000009                      127       ;***       84 : void test(char a){
    00000009 C7                   129       push hl
    0000000A 9801                 130       mov [sp+0x01], a
    0000000C                      131       ;***       85 :    char b = 0;
    0000000C C80000               133       mov [sp+0x00], #0x00
    0000000F                      135       ;***       86 :     b = a+10;
    0000000F 8801                 137       mov a, [sp+0x01]
    00000011 318E                 138       shrw ax, 8+0x00000
    00000013 040A00               139       addw ax, #0x000A
    00000016 60                   140       mov a, x
    00000017 9800                 141       mov [sp+0x00], a
    00000019                      143       ;***       87 :     R_DAC0_Set_ConversionValue(b);
    00000019 8800                 145       mov a, [sp+0x00]
    0000001B FC000000             146       call !!_R_DAC0_Set_ConversionValue
    0000001F C6                   147       pop hl
    00000020 D7                   148       ret
    00000021                      149       ;***       88 : }

    [余談]

    以前にウェブで調べていて気付いたのですが、CC-RLは情報処理学会で論文が発表されていて、その論文は優秀論文の1つとして表彰されたらしいです。

    ipsj.ixsq.nii.ac.jp/ej/?action=pages_view_main&active_action=repository_view_main_item_detail&item_id=163721&item_no=1&page_id=13&block_id=8
    RL78マイコン向けCコンパイラCC-RLにおける機種依存最適化の設計
    The Design of Target Dependent Optimizations in CC-RL, an Optimizing C Compiler for the RL78 Microcontroller
    (情報処理学会の有料コンテンツです。2018年06月06日から無料でダウンロード可能になるみたいです。)

    www.ipsj.or.jp/award/yamashita2016.html
    2016年度(平成28年度)山下記念研究賞 受賞者/論文タイトル/発表研究会略称

Reply
  • SUZUKIさん、こんにちは。NoMaYです。

    今回の件、アセンブラコードが全く分からなくても、わわいさんがアドバイスしているような、最適化のため変数への値の代入がなされなかった、ということの雰囲気が分かるような説明を考えてみました。今回の件はCC78K0Rだったのですが、インパクトが強そうな気がしましたので、説明としてはCC-RLを使うことにしました。

    まず、SUZUKIさんが書かれたコードはもともと以下のものでした。

    void test(char a){
        char b = 0;
        b = a+10;
        R_DAC0_Set_ConversionValue(b);
    }

    でも、よくよく考えると、b = 0 としたすぐ後に b = a+10 としていますので、プログラムの機能としては b = 0 は無くても良く、以下のコードで置き換えることが出来ます。

    void test(char a){
        char b;
        b = a+10;
        R_DAC0_Set_ConversionValue(b);
    }

    そうして、コードの置き換えを考え始めると、わざわざ a+10 を b に代入しなくても、以下のコードで置き換えることが出来ることに気付きます。

    void test(char a){
        R_DAC0_Set_ConversionValue(a+10);
    }

    ところで、敢えて置き換える価値はありませんが、下のように置き換えてもプログラムの機能としてはもともとのコードと等価です。ただ、この置き換えから、今回の件でウォッチで見た時に b = a+10 が実行されていないように見えた原因が何となく分かるのではないかと、思います。(人間が見れば b = 0 がプログラムの機能として意味が無いことは直ぐに分かりますが、コンパイラとしては少なくとも「a+10 を b に代入した後にその b を読み出して引数にセットする」という冗長な処理が無くなったので価値はある、だから置き換える、と判断することもあるということです。)

    void test(char a){
        char b = 0;
        R_DAC0_Set_ConversionValue(a+10);
    }

    ちなみに、CC-RLのデフォルトの最適化では、上の4つのコードは全て以下の同じアセンブラコードにコンパイルされました。(アセンブラコードの意味が分からなくても同じコードが生成されていることが伝われば良いかな、と考えました。) ソースは違うが、プログラムの機能としては同じなので、同じアセンブラコードになる、という訳です。

    00000009                      120  _test:
    00000009                      114       .STACK _test = 4
    00000009                      126       ;***       84 : void test(char a){
    00000009 0C0A                 128       add a, #0x0A
    0000000B                      129       ;***       85 :    char b = 0;
    0000000B                      130       ;***       86 :     b = a+10;
    0000000B                      131       ;***       87 :     R_DAC0_Set_ConversionValue(b);
    0000000B EC000000             133       br !!_R_DAC0_Set_ConversionValue
    0000000F                      134       ;***       88 : }
    00000009                      113  _test:
    00000009                      114       .STACK _test = 4
    00000009                      119       ;***       84 : void test(char a){
    00000009 0C0A                 121       add a, #0x0A
    0000000B                      122       ;***       85 :     char b;
    0000000B                      123       ;***       86 :     b = a+10;
    0000000B                      124       ;***       87 :     R_DAC0_Set_ConversionValue(b);
    0000000B EC000000             126       br !!_R_DAC0_Set_ConversionValue
    0000000F                      127       ;***       88 : }
    00000009                      113  _test:
    00000009                      114       .STACK _test = 4
    00000009                      119       ;***       84 : void test(char a){
    00000009 0C0A                 121       add a, #0x0A
    0000000B                      122       ;***       85 :     R_DAC0_Set_ConversionValue(a+10);
    0000000B EC000000             124       br !!_R_DAC0_Set_ConversionValue
    0000000F                      125       ;***       86 : }
    00000009                      113  _test:
    00000009                      114       .STACK _test = 4
    00000009                      119       ;***       84 : void test(char a){
    00000009 0C0A                 121       add a, #0x0A
    0000000B                      122       ;***       85 :     char b = 0;
    0000000B                      123       ;***       86 :     R_DAC0_Set_ConversionValue(a+10);
    0000000B EC000000             125       br !!_R_DAC0_Set_ConversionValue
    0000000F                      126       ;***       87 : }

    あと、プログラムの機能という点では、上のCC-RLのデフォルトの最適化ありでコンパイルしたアセンブラコードと、CC-RLで最適化無しでコンパイルした以下のアセンブラコードは、なんと等価ということになるのです。(アセンブラコードの意味が分からなくても量も内容も全然違うコードが生成されていることが伝われば良いかな、と考えました。)

    00000009                      121  _test:
    00000009                      122       .STACK _test = 6
    00000009                      127       ;***       84 : void test(char a){
    00000009 C7                   129       push hl
    0000000A 9801                 130       mov [sp+0x01], a
    0000000C                      131       ;***       85 :    char b = 0;
    0000000C C80000               133       mov [sp+0x00], #0x00
    0000000F                      135       ;***       86 :     b = a+10;
    0000000F 8801                 137       mov a, [sp+0x01]
    00000011 318E                 138       shrw ax, 8+0x00000
    00000013 040A00               139       addw ax, #0x000A
    00000016 60                   140       mov a, x
    00000017 9800                 141       mov [sp+0x00], a
    00000019                      143       ;***       87 :     R_DAC0_Set_ConversionValue(b);
    00000019 8800                 145       mov a, [sp+0x00]
    0000001B FC000000             146       call !!_R_DAC0_Set_ConversionValue
    0000001F C6                   147       pop hl
    00000020 D7                   148       ret
    00000021                      149       ;***       88 : }

    [余談]

    以前にウェブで調べていて気付いたのですが、CC-RLは情報処理学会で論文が発表されていて、その論文は優秀論文の1つとして表彰されたらしいです。

    ipsj.ixsq.nii.ac.jp/ej/?action=pages_view_main&active_action=repository_view_main_item_detail&item_id=163721&item_no=1&page_id=13&block_id=8
    RL78マイコン向けCコンパイラCC-RLにおける機種依存最適化の設計
    The Design of Target Dependent Optimizations in CC-RL, an Optimizing C Compiler for the RL78 Microcontroller
    (情報処理学会の有料コンテンツです。2018年06月06日から無料でダウンロード可能になるみたいです。)

    www.ipsj.or.jp/award/yamashita2016.html
    2016年度(平成28年度)山下記念研究賞 受賞者/論文タイトル/発表研究会略称

Children
No Data