ループの最適化

いつもお世話になっております。

以下のようなプログラムで、loop1()はwhileを抜けられず復帰しないのですが、 loop2()は、正しく復帰します。

loop1と、loop2の違いは、Delay()を呼ぶか、呼ばないかの違いしか有りません。

タイマー割り込みによりTimerは、0になります。 (Flagは0のままとします。)

多分?ループ最適化による影響ではないかと思うのですが、コンパイルオプションを替えても状況は変わりません。

どの様なオプションが影響するか お教え願えないでしょうか?

 

int Flag ;
int Timer;

void Delay( void )
  {
    asm("NOP");
  }

void Interrupt_1ms( void )
  {
    if ( Timer > 0 ) Timer--;
  }

int loop1( void )
  {
    Flag = 0;
    Timer = 100;
    while(1)
      {
        if ( Flag ) break;
        if ( Timer == 0 )
         {
           return( 1 );
         }
     }
    return( 0 );
 }

int loop2( void )
  {
    Flag = 0;
    Timer = 100;
    while(1)
      {
        Delay(); // 重要
        if ( Flag ) break;
        if ( Timer == 0 )
         {
           return( 1 );
        }
     }
    return( 0 );
  }

Parents
  • にもち さん、こんにちは。NoMaYです。お久しぶりです。

    コンパイラは何をお使いですか? RZに関して質問されていることが多いようですので、GNUARMかIAR ARM C/C++コンパイラでしょうか?

    [追記]

    あと、割り込みルーチンで更新される変数Timerにvolatileが付いていませんが、今回の質問用に付けなかったものですか? それとも、普段から付けないでいたりしますか?

Reply
  • にもち さん、こんにちは。NoMaYです。お久しぶりです。

    コンパイラは何をお使いですか? RZに関して質問されていることが多いようですので、GNUARMかIAR ARM C/C++コンパイラでしょうか?

    [追記]

    あと、割り込みルーチンで更新される変数Timerにvolatileが付いていませんが、今回の質問用に付けなかったものですか? それとも、普段から付けないでいたりしますか?

Children
  • NoMaY様 reply有難うございます。

    e2studio(GNUARM)を使用しております。(CPUは、RZ-A1l:R7S721020VCFP)

    SH4で動いていたソースをARMに移植したのですが、各所に細工が必要で手を焼いています。
    (SH4のコンパイラは、GNUとは別物です。)
  • にもち さん、こんにちは。NoMaYです。

    私の追記が行き違ったかな、という予感がするので自己レスです。これは移植元のSH4用のソースに付いていなかったから、かな、、、という気がしてきました、、、

    > [追記]
    > あと、割り込みルーチンで更新される変数Timerにvolatileが付いていませんが、今回の質問用に付けなかったものですか? それとも、普段から付けないでいたりしますか?

  • NoMaY様 有難うございました。

    volatileが抜けていました。正常に動作するようになりました。

    私は、
    普段SH4,SH2等のソフトを作っているのですが、自前のコンパイラを使用しているためvolatileと言う概念が有りませんでした。
    一昨年よりARMを手がけるようになりGNUを使用するようになったのですが、volatile未指定によると思われる現象を思い出します。
    それらも、Delay等を挟む事で解決しましたがこれが原因だったのでしょう。

    本当に有難うございました。
  • わわいです
    コンパイラは、volatileがついていない変数は、外部から変更されることがない、という前提で最適化を行います。だもんで、提示のコードではFlagが0という前提で最適化を行い、ループの途中で無駄なFlag変数の参照を省略して、高速なコードを生成します
    Delay関数を挟んだら動く、というのは、単にそのコンパイラの最適化が足りない結果そうなったということができます。他のコンパイラだとまた結果は変わるでしょうね。

    #まあ、最適化が足りない、というより、組み込み向けコンパイラなのでそういう配慮があった、のかもしれません
  • わわい様。 いつも有難うございます。

    変数Timerは、別ソース上にあるタイマー割り込みで更新しておりloop1/2のソース上には外部参照(volatile無し)で行っています。
    従って、loop1()では外部コールも発生しないためTime、Flagrの更新は無いとし、 loop2()では、外部コール(Delay)で制御が切れるためTimerや、Flagの更新を考慮したコードが出たのですね。

    e2studio(gnu)でvolatileを指定しないでも、volatile属性を有効にするオプションはあるでしょうか?
    それとも、最適化レベル(none)で行うのでしょうか? .....これは、試してみます。

    いろいろと有難うございました。
  • GCCでは変数のオプションとしては以下のものがありますね
    -fvolatile
    -fvolatile-global
    -fvolatile-static
    詳細は検索してみてください
  • > GCCでは変数のオプションとしては以下のものがありますね

    大昔に廃止になってるので今使える状況は稀でしょう。

    https://www.gnu.org/software/gcc/gcc-3.4/changes.html
    > GCC no longer accepts the options -fvolatile, -fvolatile-global and -fvolatile-static. It is unlikely that they worked correctly in any 3.x release.