Top Page [◀◀]  2   3   4   5   6   7   8   9   ... [▶▶Last Page

HEWで最適化レベルを変えてみたら、「えっ!?」の連続

 下記のプログラムなら最適化レベルによらず同じコードになると思い実験してみました。

「最適化レベル 0」のときに、どうしてこんなに長くなるのでしょうか。

goto文のコードが出て来ない。

こんなコンパイラで、今まで問題無かったのか?

CPUは、RX621です。

 

●最適化レベル Max

{ unsigned long N = 0x000800000 ; while (--N) ; } // ソフトタイマー
MOV.L       #00800000H,R5
SUB         #1H,R5
BNE.B       L11


●最適化レベル 0

{ unsigned long N = 0x000800000 ; while (--N) ; } // ソフトタイマー
 L10      MOV.L       #00800000H,R5
          MOV.L       R5,R14
          MOV.L       R14,[R0]
          MOV.L       [R0],R14
          SUB         #1H,R14
          MOV.L       R14,[R0]
          MOV.L       [R0],R14
          MOV.L       R14,R5
          CMP         #0H,R5
          BEQ.B       L11
 L12      MOV.L       [R0],R14
          SUB         #1H,R14
          MOV.L       R14,[R0]
          MOV.L       [R0],R14
          MOV.L       R14,R5
          CMP         #0H,R5
          BNE.B       L12
 L11

 

●最適化レベル 0

while (1)    ; // 無限ループでストップ
L13      MOV.L       #0H,R14
         CMP         #1H,R14
         BEQ.S       L11
L15      MOV.L       #0H,R14
         CMP         #1H,R14
         BNE.B       L15
L11      BRA.B       L11


●最適化レベル Max

while (1)    ; // 無限ループでストップ
L14      BRA.B       L14


●最適化レベル 0

  9 { unsigned long N = 0x000800000 ; while (--N) ; } // ソフトタイマー
     00001182 FB5200008000     L12      MOV.L       #00800000H,R5
     00001188 EF5E                      MOV.L       R5,R14
     0000118A E30E                      MOV.L       R14,[R0]
     0000118C EC0E                      MOV.L       [R0],R14
     0000118E 601E                      SUB         #1H,R14
     00001190 E30E                      MOV.L       R14,[R0]
     00001192 EC0E                      MOV.L       [R0],R14
     00001194 EFE5                      MOV.L       R14,R5
     00001196 6105                      CMP         #0H,R5
     00001198 2010                      BEQ.B       L11
     0000119A EC0E             L13      MOV.L       [R0],R14
     0000119C 601E                      SUB         #1H,R14
     0000119E E30E                      MOV.L       R14,[R0]
     000011A0 EC0E                      MOV.L       [R0],R14
     000011A2 EFE5                      MOV.L       R14,R5
     000011A4 6105                      CMP         #0H,R5
     000011A6 21F4                      BNE.B       L13
     000011A8 2E00             L11      BRA.B       L11
  10
  11 Loop:
  12 goto Loop  ; // 無限ループでストップ

 上の { unsigned long N = 0x000800000 ; while (--N) ; } のコードは出力されているのに、
「goto Loop」のマシン語コードが無い。
 「Loop:」を削除すると、Loop が無いと言うエラーになるので、「goto Loop」を認識している筈だ。

  • 「 「goto Loop」のマシン語コードが無い。 」トラブルだけど、
    「 000011A8 2E00 L11 BRA.B L11 」 の部分のようです。

     しかしC言語のテキストの後にマシン語の筈なのに、何でここだけ違うのだろう。
  • In reply to リカルド:

    なんかおかしいですか?
  • In reply to fujita nozomu:

    fujita nozomu さん、

    while (1) が1命令で済むのに、「最適化レベル 0」だと7命令にもなっているんですよ。
    while (1)  をどのように解釈したら、7命令にもなるんでしょう。おかしいと感じませんか?
  • In reply to リカルド:

    > while (1)  をどのように解釈したら、7命令にもなるんでしょう。

    L13      MOV.L       #0H,R14
             CMP         #1H,R14
             BEQ.S       L11 
    L15      MOV.L       #0H,R14
             CMP         #1H,R14
             BNE.B       L15 
    L11
    

    ↑ は

            if (1 != 0) {
                L15:
                    /* whileで実行される内容 */
                    ;
                if (1 != 0) goto L15;
            }
    

    に相当し、while の形式で無限ループは構成できてるので 6命令では?

    > おかしいと感じませんか?

    無限ループの後に更に

    L11      BRA.B       L11
    

    無限ループが続くのはおかしいと感じますが、

    while (1)    ; // 無限ループでストップ
    

    の後に

    Loop:
        goto Loop  ; // 無限ループでストップ
    

    等書かれてはいませんか?

  • わわいです
    最適化レベル0だと、最適化されないってことなので、そんなもんだと思いますが。
    なにかおかしいところはあるんでしょうか
  • In reply to fujita nozomu:

    fujita nozomu さん、わざわざ解釈を考えてくれたんですか。有難う。

     定数なのに比較命令が有るのはおかしいと思いませんか。
     ゼロかどうか調べるには、自分自身とANDやORを取るのが常套手段だと思いますが、
    わざわざ0と比較なんかするのかね。
    while (1)  には {}  が無いんだから次のようになるのが自然じゃないのか。

    L13 MOV.L #0H,R14
    CMP #1H,R14
    BEQ.S L11
       L13 にジャンプ


    >Loop:
    > goto Loop ; // 無限ループでストップ
    >等書かれてはいませんか?

    2019/1/1 15:50  付けで書いた通り、goto Loop ;  が有ります。

     C言語のソースコードの後にマシン語が続くのに、ここだけマシン語が前に来てます。
    奇妙だな。
  • In reply to リカルド:

    >  定数なのに比較命令が有るのはおかしいと思いませんか。

    最適化レベル0で出力されたコードにそういう感想は持たないですね。

    >  ゼロかどうか調べるには、自分自身とANDやORを取るのが常套手段だと思いますが、

    > わざわざ0と比較なんかするのかね。

    RX の命令で CMP #UIMM:4, Rs と AND Rs, Rd や OR Rs, Rd で命令長や実行サイクル数に違いがないのでどうでも良いことと思います。

    > while (1)  には {}  が無いんだから次のようになるのが自然じゃないのか。

    最適化されたコードを期待するなら素直に最適化指示を行いましょう。

  • In reply to リカルド:

    新年あけましておめでとうございます。
    タイトルに「HEWで」とあるので、CC-RX V1を使われているようですね。
    手元のHEW環境にあった、CC-RX V.1.02.01で試したところ、最適化レベル0では無駄なコードが出まくっていました。最適化レベル1にすると、かなりまともになります。(デバッグに一部制限は付きますが)
    ちなみに、CC-RX V2以降は最適化モジュールが一新されており、手元のCS+にあった、CC-RX V2.08.00で確認したところ、最適化レベル0で割とまともなコードを吐き出しています。
  • In reply to Higetaka:

    Higetaka さん、調べてくれて有難う御座います。
    H8/3048 のコンパイルなども行って調べて見ました。
    最適化しなくても、while (1) は BRA L84:8 と、1命令のジャンプになっていました。

    === H8/3048  C言語 ソースファイル===
    int main(void)
    {
    //((void(*)(void))0x0010000)( ) ;
    while (1) ;
    //return;
    }

    === H8/3048  コンパイル結果 ===
    _main: ; function: main
    .STACK _main=8
    PUSH.L ER6
    MOV.L SP,ER6
    .LINE 7
    .LINE 9
    BRA L85:8
    L84:
    L85:
    .LINE 9
    BRA L84:8
    .LINE 11
    POP.L ER6
    RTS


     RX621のソフトタイマーが長い理由は、変数 N をスタック領域に書き込んでいるからでしょう。
    割り込み処理で スタック領域の N を調べれば、N の変化が分るようになっている。
     それならばレジスター変数にすれば、スタック領域に書かなくなるだろうと思い実験してみました。
     結果は、変わらずです。register を書いても、無視されるようです。

    9 { unsigned long N = 0x000800000 ; while (--N) ; } // ソフトタイマー
    00001182 FB5200008000 L12 MOV.L #00800000H,R5
    00001188 EF5E MOV.L R5,R14
    0000118A E30E MOV.L R14,[R0]
    0000118C EC0E MOV.L [R0],R14
    0000118E 601E SUB #1H,R14
    00001190 E30E MOV.L R14,[R0]
    00001192 EC0E MOV.L [R0],R14
    00001194 EFE5 MOV.L R14,R5
    00001196 6105 CMP #0H,R5
    00001198 2010 BEQ.B L13
    0000119A EC0E L14 MOV.L [R0],R14
    0000119C 601E SUB #1H,R14
    0000119E E30E MOV.L R14,[R0]
    000011A0 EC0E MOV.L [R0],R14
    000011A2 EFE5 MOV.L R14,R5
    000011A4 6105 CMP #0H,R5
    000011A6 21F4 BNE.B L14
    10
    11
    12 { register unsigned long N = 0x000800000 ; while (--N) ; } // ソフトタイマー
    000011A8 FB5200008000 L13 MOV.L #00800000H,R5
    000011AE EF5E MOV.L R5,R14
    000011B0 E70E01 MOV.L R14,04H[R0]
    000011B3 ED0E01 MOV.L 04H[R0],R14
    000011B6 601E SUB #1H,R14
    000011B8 E70E01 MOV.L R14,04H[R0]
    000011BB ED0E01 MOV.L 04H[R0],R14
    000011BE EFE5 MOV.L R14,R5
    000011C0 6105 CMP #0H,R5
    000011C2 2013 BEQ.B L11
    000011C4 ED0E01 L15 MOV.L 04H[R0],R14
    000011C7 601E SUB #1H,R14
    000011C9 E70E01 MOV.L R14,04H[R0]
    000011CC ED0E01 MOV.L 04H[R0],R14
    000011CF EFE5 MOV.L R14,R5
    000011D1 6105 CMP #0H,R5
    000011D3 21F1 BNE.B L15
    000011D5 2E00 L11 BRA.B L11
    13
    14
    15
    16 Loop: goto Loop ; // 無限ループでストップ
    17
  • In reply to リカルド:

    > 最適化しなくても、while (1) は BRA L84:8 と、1命令のジャンプになっていました。

    .LINE 9
    BRA L85:8
    L84: 
    L85: 
    .LINE 9
    BRA L84:8    
    

    2命令だと思います。

  • In reply to fujita nozomu:

    >2命令だと思います。

     んっ?良く細かい所まで見ていますね。
     「ストップさせるには自分自身にジャンプする1命令でいいのに、RX621では冗長な命令になっている。
     H8ではループ部分が1命令になっているから、対象CPUとそのCコンパイラによって違う。」と言う事を言いたかったので、「ループ部分が1命令」と言う部分に着目して書きました。
     fujita nozomu さんから指摘されて、最初の命令は何ためか考えました。
     以前にH8で調べた事が有ります。
     while(判断){繰り返し処理} をそのままアセンブラに直すと次のようになります。

    L1:
     判断
     脱出条件でL2にジャンプ
     繰り返し処理
     L1にジャンプ
    L2:

     これを次のように改善すると「L1にジャンプ」の無条件ジャンプ部分が除かれ、ループ時間が短くなる。

     L2にジャンプ
    L1:
     繰り返し処理
    L2:
     判断
     繰り返し条件でL1にジャンプ

     while(1) は、「繰り返し処理」部分が無くなっているので、「L2にジャンプ」部分が無意味なジャンプに見えている。

     do{}while (1) にしたらどうなるか、調べてみました。

    == H8 最適化無し ==

    while (1) ;

    do{}while (1) ;


    BRA L86:8
    L85:
    L86:
    .LINE 9
    BRA L85:8
    .LINE 11
    L87:
    .LINE 11
    .LINE 11
    BRA L87:8

     do{}while (1) だと余計なジャンプが無くなります。
     while (1){} の括弧を省略して while (1) と書けるのなら、do{}while (1) を do while (1) と書けるのか試したところエラーになりました。
     RX621での do{}while (1) について、調べてみました。

    == RX621 最適化レベル0 ==

    11 do{}while(1) ;
    0000118D 660E L14 MOV.L #0H,R14
    0000118F 611E CMP #1H,R14
    00001191 21FC BNE.B L14
    00001193 2E00 L11 BRA.B L11
    12
    13 Loop: goto Loop ; // 無限ループでストップ


     プログラムを停止するのに while (1) が良く使われていますが、do{}while (1) の方が良さそうです。
     更に goto の方が、コンパイラに依らず短く速い結果が得られそうです。
  • In reply to リカルド:

    > while (1){} の括弧を省略して while (1) と書けるのなら、do{}while (1) を do while (1) と書けるのか試したところエラーになりました。

    繰り返しの書式は

    while (式) 文
    

    do 文 while (式);
    

    なので do ; while (1); では

    https://godbolt.org/z/OCsQ3r

  • In reply to fujita nozomu:

    >https://godbolt.org/z/OCsQ3r

     ページが白紙ですが、何処を見るのでしょう?

    >なので do ; while (1); では

     do ; のセミコロンで  do while 文が終了して「対応する while が無い」と言うエラーになるのかと思ったら、これでも動きますね。

     「  「do .. while」文で、処理が1つの場合は括弧で囲わなくても構わない 」と言う理由なのですね。

      do 処理 ; while (1);  の処理部分が空白になったと言う事ですね。
     括弧を省いた事は無いので、そこまでは気付かなかったな。
     fujita nozomu  さんは、良く細かい所まで知ってますね。
  • In reply to リカルド:

    > 良く細かい所まで知ってますね。

    知識は大したことありませんが不明点は確認するよう心がけています。

Top Page [◀◀]  2   3   4   5   6   7   8   9   ... [▶▶Last Page