お世話になります。SYOUです。
RX62Tでソフトを作っていて、作成したコードにアドレスが割り当てられず、ブレークポイントを置けなくて困っているので投稿させてもらいます。(開発環境はCS+になります)
下に簡単に関数を書いたのですがこの関数をCS+でビルドしてみたところPos=i;のところにアドレスが表示されず、ブレークポイントが設置できません。
関数の内容をほかのところに直接書いた場合にはアドレスも表示され、ブレークポイントの設定もできました。
似たような状況になったことのある方いらっしゃいましたらお知恵をお借りしたいです。
void f(uint_16 j ,uint_8 k ,uint_32 Pos ){
uint_16 i;
for(m=0; j<10; m++){
if( (box[ m ]==j) && (k==1) ){
Pos = i;
}
わわいです。
Posという変数が代入されるだけで参照されないため、コンパイラの最適化でその命令が削除されてますね。
#また、変数 i に値が入ってません
これをどーにかするには、お使いのコンパイラの設定で、最適化を「なし」にするか、「デバッグ用」、にするかしてコンパイルし直してみればいいです
void f(uint_16 j ,uint_8 k ,uint_32 Pos ){ uint_16 i; for(m=0; j<10; m++){ if( (box[ m ]==j) && (k==1) ){ Pos = i; } } }
CS+ の挙動以前の話として、書かれてるプログラムの見直しをお勧めします。
どのようにアセンブラに変換されたのか見たらどうですか。
わわいさん
最適化を「なし」にしてコンパイルをしたら治りました。ありがとうございました。
fujitaさん
簡単にしようとして大部分を削ったつもりだったのですが、そのせいでよくわからないソフトになってしまっていました。すいません。
Posの型はそのままなので参照型への変更を考えたいと思います。
リカルドさん
混合状態で確認してみたのですがよくわからないところに飛んでしまっていて理解できなかったので、何かヒントになればと思い、質問させてもらいました。
(アセンブラが詳しくないせいなのですが…)
追加の質問になりますが、最適化をそのままの状態にして治す方法などはあるのでしょうか?
なるべくならば今までの最適化レベルでプログラムを進めていきたいと考えているのでもしできるのであれば教えていただきたいです。
> 最適化をそのままの状態にして治す方法などはあるのでしょうか?
Pos が参照型になっていれば最適化が有効でも削除されることはありません。
SYOUさん、こんにちは。
議論を
(1)このプログラム特有の挙動
(2)最適化の一般論
の2つに分けて考えてはどうだろうかと思いました。
(1)に関しては藤田様の回答が正にそれだと思います。
(2)に関してはわわい様の回答に関連する話で、言葉の定義からして、最適化を掛けるということは無駄なコードを削除する、
ということでもありますので、削除されてデバッグし難くなるのであれば最適化を掛けないようにする、しかないです。一般的に
良く行われているのは、プログラマさんのPC上でのデバッグ時のみ最適化を掛けないでデバッグして、評価仕様書に基づく
単体検査なり結合検査なりは最適化を掛けた状態でビルドしたプログラムで行う方法です。
逆に、初心者のうちは、最適化はなしにしといたほうがいいです。
さもないと、自分の思うように動いてくれない場合が出てきて、ムダに時間を取られることになったりします。
最適化をONにしたところで、ゆーほど動作速度が早くなったりするもんでもないですし、最適化で削れるオブジェクトサイズなんか、いまどきでは問題にもならないですしねえ。
fujita nozomuさん
>Pos が参照型になっていれば最適化が有効でも削除されることはありません。
これは、ルネサスコンパイラなら正しいのですが、GCCなんかだと正しくなくなったりします。
過去にこれについての議論があったので、検索していただければでてくるかとおもいます。
まー、最適化の可否についてはいろいろ議論が分かれるところではありますが。。
gcc version 4.8.0.201603-GNURX (GCC_Build_20160903) にて正しい結果となることを確認しました。
$ cat -n test.cpp 1 typedef unsigned char uint_8; 2 typedef unsigned short uint_16; 3 typedef unsigned long uint_32; 4 extern uint_8 box[]; 5 6 void f(uint_16 j ,uint_8 k ,uint_32 Pos ){ 7 uint_16 i; 8 for(i=0; i<10; i++){ 9 if( (box[ i ]==j) && (k==1) ){ 10 Pos = i; 11 } 12 } 13 } 14 15 void g(uint_16 j ,uint_8 k ,uint_32& Pos ){ 16 uint_16 i; 17 for(i=0; i<10; i++){ 18 if( (box[ i ]==j) && (k==1) ){ 19 Pos = i; 20 } 21 } 22 } $ rx-elf-gcc -O2 -g -c test.cpp ; rx-elf-objdump -S test.o test.o: file format elf32-rx-le Disassembly of section P: 00000000 <__Z1fthm>: typedef unsigned char uint_8; typedef unsigned short uint_16; typedef unsigned long uint_32; extern uint_8 box[]; void f(uint_16 j ,uint_8 k ,uint_32 Pos ){ 0: 02 rts 00000001 <__Z1gthRm>: Pos = i; } } } void g(uint_16 j ,uint_8 k ,uint_32& Pos ){ 1: fb e2 00 00 00 00 mov.l #0, r14 7: 5f 11 movu.w r1, r1 00000009 <.LBB2>: uint_16 i; for(i=0; i<10; i++){ if( (box[ i ]==j) && (k==1) ){ 9: 5b 22 movu.b r2, r2 b: fc 3b e5 not r14, r5 e: 0a bra.s 18 <.LBB2+0xf> } } void g(uint_16 j ,uint_8 k ,uint_32& Pos ){ uint_16 i; for(i=0; i<10; i++){ f: 74 0e 00 00 00 00 cmp #0, r14 15: 20 1b beq.b 30 <.LBB2+0x27> 17: 03 nop if( (box[ i ]==j) && (k==1) ){ 18: fd 38 e4 movu.b [r14+], r4 1b: 47 14 cmp r1, r4 1d: 21 f2 bne.b f <.LBB2+0x6> 1f: 61 12 cmp #1, r2 21: 21 ee bne.b f <.LBB2+0x6> 23: ff 24 e5 add r14, r5, r4 Pos = i; 26: e3 34 mov.l r4, [r3] } } void g(uint_16 j ,uint_8 k ,uint_32& Pos ){ uint_16 i; for(i=0; i<10; i++){ 28: 74 0e 00 00 00 00 cmp #0, r14 2e: 21 ea bne.b 18 <.LBB2+0xf> if( (box[ i ]==j) && (k==1) ){ Pos = i; } } } 30: 02 rts 31: fd 70 40 00 00 00 80 nop ; max #0x80000000, r0 $
ページ右上の検索で「GCC」や「GNU」を検索してみましたがそれらしい議論は見当たりませんでした。それ以上の確認はしてません。
SYOUさん
「最適化される」という挙動は全て、「最適化できる根拠がある」からされる、と思って下さい。例えば以下のプログラム
①int a,b;
②a = 2;
③b = 5
④a = 20;
こんなカンジで①から④まで実行されるプログラムがある場合。④でaに20が入るなら、その間にaが使われてないから、②のa=2は無駄だろ!俺が消してやるわ!という親切心が、「最適化」です。
ここで問題になるのが、③のあたりでブレークポイント貼ってICEとかで値を見たい場合。②が消されてるので、ICEで見るとaは「不定値」だったりします。こうなるとワケが判らなくなり、環境がおかしいとかマイコンバグだとか変な議論になります。
また、割り込みなどで取得した値をGLOBAL変数に保存しておき、これをメインループで処理する、等の手法を用いる場合がありますが、これも最適化では消されたりします。割り込み内で「参照されない変数」とコンパイラが判断したら、じゃあ無駄だから消すね、と消してくれちゃいます。
なぜ最適化で消されるか、という理屈を理解すれば、「最適化に振り回されない作り方」が出来るようになりますよー。