ループの最適化

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

以下のようなプログラムで、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
  • > 多分?ループ最適化による影響ではないかと思うのですが、

    Cコンパイラは「ひとつの関数の中では volatile 指定されていないオブジェクトの内容は勝手に変化しない」前提でコード生成するので loop1() の中の処理では Flag は 0、Timer は 100 に初期化して以降、その状態が続く(ループ処理が終わらない)コードが生成されると思います。https://godbolt.org/z/X3NRVB

    対して loop2() では、ループ処理の中で呼んでる関数 Delay() の中でインラインアセンブラが使用されており、コンパイラはインラインアセンブラの処理内容を理解しないため、そのわからない処理の中で Flag や Timer の内容が書き換えられる可能性を考慮してループ中に Flag や Timer のアクセスの度に内容をメモリから読み出します。https://godbolt.org/z/6-VZlk
    loop2() が復帰する理由はそれでしょう。
    Delay() の中のインラインアセンブラを無効化すれば Delay() の処理で Flag や Timer の内容が書き変わらないことをコンパイラは理解するのでループ処理は終わらなくなるかもしれません。https://godbolt.org/z/PIVpif
    同様に、Delay() を外部関数化して処理の内容をコンパイラに悟られないようすれば Loop2() は復帰するコードになるかもしれません。https://godbolt.org/z/5y2Mwb

    > コンパイルオプションを替えても状況は変わりません。

    大昔の gcc では volatile 指定されていないオブジェクトを volatile 指定されているよう扱うコンパイルオプションが存在しましたが既に廃止されています。最適化レベル0を指定(`-O0')すれば一見うまくいくようなコードは生成されるかもしれませんが https://godbolt.org/z/TMilv8 「ひとつの関数の中では volatile 指定されていないオブジェクトの内容は勝手に変化しない」前提は変わらないので期待したコードが生成されるかは何の保証もありません。割り込み処理で変化をさせるオブジェクトについては素直に volatile 指定をする以外方法はないでしょう。

  • fujita nozomu様

    詳細な解説有難うございました。
    上位のコンピュータ(昔の表現?)用のソフトでは意識しなかったり、以前使用していたコンパイラがループの最適化を行わない仕様であったりしたため 今回の不具合をvolatile未指定によるものと考えませんでした。
    今後は、使用するコンパイラが一般的なものであると意識して使用したいと思います

    ありがとうございました。
Reply
  • fujita nozomu様

    詳細な解説有難うございました。
    上位のコンピュータ(昔の表現?)用のソフトでは意識しなかったり、以前使用していたコンパイラがループの最適化を行わない仕様であったりしたため 今回の不具合をvolatile未指定によるものと考えませんでした。
    今後は、使用するコンパイラが一般的なものであると意識して使用したいと思います

    ありがとうございました。
Children
No Data