RX62T 実行されないコード

お世話になります。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;
    
      }
    
     }
    
    }
    
    • 引数 j の値がループ内で変化しないため、j<10 の条件が成り立つ場合には無限ループとなります
    • ループ変数 m を使用されていますが関数内に変数宣言がなく大域変数を使用されてるのかと思われますが、大域変数に短い名前を使用したり局所的用途に使用するのはバグの元です
    • ループ内で条件に一致した場合、引数 Pos に未初期化変数 i の値を代入されてますが、Pos で関数の外に結果を返したいのであれば、Pos の型は参照型にすべきと思われます。変数 i の値が未初期化で Pos に代入してるのも気になります

    CS+ の挙動以前の話として、書かれてるプログラムの見直しをお勧めします。

  •  どのようにアセンブラに変換されたのか見たらどうですか。

  • わわいさん

    最適化を「なし」にしてコンパイルをしたら治りました。ありがとうございました。

    fujitaさん

    簡単にしようとして大部分を削ったつもりだったのですが、そのせいでよくわからないソフトになってしまっていました。すいません。

    Posの型はそのままなので参照型への変更を考えたいと思います。

    リカルドさん

    混合状態で確認してみたのですがよくわからないところに飛んでしまっていて理解できなかったので、何かヒントになればと思い、質問させてもらいました。

    (アセンブラが詳しくないせいなのですが…)

    追加の質問になりますが、最適化をそのままの状態にして治す方法などはあるのでしょうか?

    なるべくならば今までの最適化レベルでプログラムを進めていきたいと考えているのでもしできるのであれば教えていただきたいです。

  • わわいさん

    最適化を「なし」にしてコンパイルをしたら治りました。ありがとうございました。

    fujitaさん

    簡単にしようとして大部分を削ったつもりだったのですが、そのせいでよくわからないソフトになってしまっていました。すいません。

    Posの型はそのままなので参照型への変更を考えたいと思います。

    リカルドさん

    混合状態で確認してみたのですがよくわからないところに飛んでしまっていて理解できなかったので、何かヒントになればと思い、質問させてもらいました。

    (アセンブラが詳しくないせいなのですが…)

    追加の質問になりますが、最適化をそのままの状態にして治す方法などはあるのでしょうか?

    なるべくならば今までの最適化レベルでプログラムを進めていきたいと考えているのでもしできるのであれば教えていただきたいです。

  • > 最適化をそのままの状態にして治す方法などはあるのでしょうか?

    Pos が参照型になっていれば最適化が有効でも削除されることはありません。

  • SYOUさん、こんにちは。

    議論を

    (1)このプログラム特有の挙動

    (2)最適化の一般論

    の2つに分けて考えてはどうだろうかと思いました。

    (1)に関しては藤田様の回答が正にそれだと思います。

    (2)に関してはわわい様の回答に関連する話で、言葉の定義からして、最適化を掛けるということは無駄なコードを削除する、

    ということでもありますので、削除されてデバッグし難くなるのであれば最適化を掛けないようにする、しかないです。一般的に

    良く行われているのは、プログラマさんのPC上でのデバッグ時のみ最適化を掛けないでデバッグして、評価仕様書に基づく

    単体検査なり結合検査なりは最適化を掛けた状態でビルドしたプログラムで行う方法です。

  • わわいです。

    逆に、初心者のうちは、最適化はなしにしといたほうがいいです。

    さもないと、自分の思うように動いてくれない場合が出てきて、ムダに時間を取られることになったりします。

    最適化をONにしたところで、ゆーほど動作速度が早くなったりするもんでもないですし、最適化で削れるオブジェクトサイズなんか、いまどきでは問題にもならないですしねえ。

    fujita nozomuさん

    >Pos が参照型になっていれば最適化が有効でも削除されることはありません。

    これは、ルネサスコンパイラなら正しいのですが、GCCなんかだと正しくなくなったりします。

    過去にこれについての議論があったので、検索していただければでてくるかとおもいます。

    まー、最適化の可否についてはいろいろ議論が分かれるところではありますが。。

  • >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変数に保存しておき、これをメインループで処理する、等の手法を用いる場合がありますが、これも最適化では消されたりします。割り込み内で「参照されない変数」とコンパイラが判断したら、じゃあ無駄だから消すね、と消してくれちゃいます。

    なぜ最適化で消されるか、という理屈を理解すれば、「最適化に振り回されない作り方」が出来るようになりますよー。