こんにちは。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共にアドレスが割り当てられ正常に動作しました。
これはどのような事が起きているのでしょうか。
宜しくお願い致します。
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 = 400000009 126 ;*** 84 : void test(char a){00000009 0C0A 128 add a, #0x0A0000000B 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_ConversionValue0000000F 134 ;*** 88 : }
00000009 113 _test:00000009 114 .STACK _test = 400000009 119 ;*** 84 : void test(char a){00000009 0C0A 121 add a, #0x0A0000000B 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_ConversionValue0000000F 127 ;*** 88 : }
00000009 113 _test:00000009 114 .STACK _test = 400000009 119 ;*** 84 : void test(char a){00000009 0C0A 121 add a, #0x0A0000000B 122 ;*** 85 : R_DAC0_Set_ConversionValue(a+10);0000000B EC000000 124 br !!_R_DAC0_Set_ConversionValue0000000F 125 ;*** 86 : }
00000009 113 _test:00000009 114 .STACK _test = 400000009 119 ;*** 84 : void test(char a){00000009 0C0A 121 add a, #0x0A0000000B 122 ;*** 85 : char b = 0;0000000B 123 ;*** 86 : R_DAC0_Set_ConversionValue(a+10);0000000B EC000000 125 br !!_R_DAC0_Set_ConversionValue0000000F 126 ;*** 87 : }
あと、プログラムの機能という点では、上のCC-RLのデフォルトの最適化ありでコンパイルしたアセンブラコードと、CC-RLで最適化無しでコンパイルした以下のアセンブラコードは、なんと等価ということになるのです。(アセンブラコードの意味が分からなくても量も内容も全然違うコードが生成されていることが伝われば良いかな、と考えました。)
00000009 121 _test:00000009 122 .STACK _test = 600000009 127 ;*** 84 : void test(char a){00000009 C7 129 push hl0000000A 9801 130 mov [sp+0x01], a0000000C 131 ;*** 85 : char b = 0;0000000C C80000 133 mov [sp+0x00], #0x000000000F 135 ;*** 86 : b = a+10;0000000F 8801 137 mov a, [sp+0x01]00000011 318E 138 shrw ax, 8+0x0000000000013 040A00 139 addw ax, #0x000A00000016 60 140 mov a, x00000017 9800 141 mov [sp+0x00], a00000019 143 ;*** 87 : R_DAC0_Set_ConversionValue(b);00000019 8800 145 mov a, [sp+0x00]0000001B FC000000 146 call !!_R_DAC0_Set_ConversionValue0000001F C6 147 pop hl00000020 D7 148 ret00000021 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=8RL78マイコン向け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.html2016年度(平成28年度)山下記念研究賞 受賞者/論文タイトル/発表研究会略称