CS+のコード生成ツールが生成するポインタ変数でvolatile修飾子の記述位置がおかしいものがあるように思います

藤田様の別スレッドに便乗なのですが、CS+のRL78のコード生成ツールが生成するuart通信機能のポインタ変数でvolatile修飾子の記述位置がおかしいものがあるように思います。具体的な変数名で言うと、gp_uart0_tx_addressとgp_uart0_rx_addressです。(CS+ for CC V5.00.00のコード生成機能で確認しました。)

コード生成ツールが生成した変数宣言は以下の通りです。

volatile uint8_t * gp_uart0_tx_address;         /* uart0 send buffer address */

volatile uint8_t * gp_uart0_rx_address;         /* uart0 receive buffer address */

ところが、以下の画面コピーの赤枠の箇所の通り、割り込みルーチン内で変更されるのはgp_uart0_tx_addressやgp_uart0_rx_addressの変数自身ですので以下の変数宣言が正しい気がします。

uint8_t * volatile gp_uart0_tx_address;         /* uart0 send buffer address */

uint8_t * volatile gp_uart0_rx_address;         /* uart0 receive buffer address */

試しに型修飾子の作用の仕方がvolatileと同様なconst(型修飾子の作用自体(機能)としては対義語的になる)で試してみると、変数自身に作用したのは以下の画面コピーのように橙枠の方でしたので、volatileも変数自身に作用させる場合には同様である筈です。

Parents
  • fujita nozomu さん、他のコンパイラーの結果を有難うございます。
     結果を以下にまとめてみました。
     fujita さんの薄青の画面をエディタにコピーすると、スペースも入り難無く見られます。
     しかしそれを加工して投稿すると、スペースなどが消えて見難くなります。
     Reply を押すまでは、正常に表示しているのに。
     薄青の画面はどうやって作るのですか?

    extern volatile int* hogehoge;

    void hoge(void) {while (*hogehoge) ;}
    void hogera(void) {while (hogehoge) ;}


    extern int* volatile piyopiyo;

    void piyo(void) {while (*piyopiyo) ;}
    void piyora(void) {while (piyopiyo) ;}

    ----------------------------------------------

    「extern volatile int* hogehoge;」の場合

    _hoge:
    movw bc, !LOWW(_hogehoge)  この命令は1回のみ実行
    .BB@LABEL@2_1: ; bb1
    movw ax, 0x0000[bc]
    or a, x
    bnz $.BB@LABEL@2_1
    ret
     
    _hogera: 一度しかチェックしない。ゼロ以外なら、無限ループから抜けない。
    movw ax, !LOWW(_hogehoge)
    or a, x
    sknz       この命令は「ゼロで無ければ .BB@LABEL@3_2: に飛ぶ?」
    ret
    .BB@LABEL@3_2: ; bb1
    br $.BB@LABEL@3_2

    ---------------------------------------------

    「extern int* volatile piyopiyo;」の場合

    _piyo:
    .BB@LABEL@4_1: ; bb1
    movw bc, !LOWW(_piyopiyo) この命令は毎回実行
    movw ax, 0x0000[bc]
    or a, x
    bnz $.BB@LABEL@4_1
    ret

    _piyora:        何度もチェックしている
    .BB@LABEL@5_1: ; bb1
    movw ax, !LOWW(_piyopiyo)
    or a, x
    bnz $.BB@LABEL@5_1
    ret
     
     
     確かに違いが有りますね。インターネットで次の記事を見つけました。
     
    sunafukin2go.hatenablog.com/.../014148
    こういった場合にvolatile unsigned char *piAddr;をして、この最適化を抑制します。
    なお補足しておきますが、unsigned char * volatile piAddr; とするとアドレスが最適化されないという意味になります。
    基本的にはアドレスの指す先が最適化されないというのが一般的ではないかと思います。
     
     
     volatile の位置の違いによる差がよく分からない。
     「extern int* volatile piyopiyo;」の場合は、piyo と piyora の両方に利いて、「extern volatile int* hogehoge;」の場合は hoge と hogera の両方に利かなかったと言う事にならないかな。
     コンパイラを作る人の解釈の違い?
Reply
  • fujita nozomu さん、他のコンパイラーの結果を有難うございます。
     結果を以下にまとめてみました。
     fujita さんの薄青の画面をエディタにコピーすると、スペースも入り難無く見られます。
     しかしそれを加工して投稿すると、スペースなどが消えて見難くなります。
     Reply を押すまでは、正常に表示しているのに。
     薄青の画面はどうやって作るのですか?

    extern volatile int* hogehoge;

    void hoge(void) {while (*hogehoge) ;}
    void hogera(void) {while (hogehoge) ;}


    extern int* volatile piyopiyo;

    void piyo(void) {while (*piyopiyo) ;}
    void piyora(void) {while (piyopiyo) ;}

    ----------------------------------------------

    「extern volatile int* hogehoge;」の場合

    _hoge:
    movw bc, !LOWW(_hogehoge)  この命令は1回のみ実行
    .BB@LABEL@2_1: ; bb1
    movw ax, 0x0000[bc]
    or a, x
    bnz $.BB@LABEL@2_1
    ret
     
    _hogera: 一度しかチェックしない。ゼロ以外なら、無限ループから抜けない。
    movw ax, !LOWW(_hogehoge)
    or a, x
    sknz       この命令は「ゼロで無ければ .BB@LABEL@3_2: に飛ぶ?」
    ret
    .BB@LABEL@3_2: ; bb1
    br $.BB@LABEL@3_2

    ---------------------------------------------

    「extern int* volatile piyopiyo;」の場合

    _piyo:
    .BB@LABEL@4_1: ; bb1
    movw bc, !LOWW(_piyopiyo) この命令は毎回実行
    movw ax, 0x0000[bc]
    or a, x
    bnz $.BB@LABEL@4_1
    ret

    _piyora:        何度もチェックしている
    .BB@LABEL@5_1: ; bb1
    movw ax, !LOWW(_piyopiyo)
    or a, x
    bnz $.BB@LABEL@5_1
    ret
     
     
     確かに違いが有りますね。インターネットで次の記事を見つけました。
     
    sunafukin2go.hatenablog.com/.../014148
    こういった場合にvolatile unsigned char *piAddr;をして、この最適化を抑制します。
    なお補足しておきますが、unsigned char * volatile piAddr; とするとアドレスが最適化されないという意味になります。
    基本的にはアドレスの指す先が最適化されないというのが一般的ではないかと思います。
     
     
     volatile の位置の違いによる差がよく分からない。
     「extern int* volatile piyopiyo;」の場合は、piyo と piyora の両方に利いて、「extern volatile int* hogehoge;」の場合は hoge と hogera の両方に利かなかったと言う事にならないかな。
     コンパイラを作る人の解釈の違い?
Children
  • > 薄青の画面はどうやって作るのですか?

    投稿の際に'Use rich formatting' を選び、「Tools」→「<> Source code」を選択して HTML 編集を行い、コードは <pre> ~ </pre> で囲んでいます。

  • リカルドさん、こんにちは。

    リカルドさまwrote: said:
    インターネットで次の記事を見つけました。
     
    sunafukin2go.hatenablog.com/.../014148
    こういった場合にvolatile unsigned char *piAddr;をして、この最適化を抑制します。
    なお補足しておきますが、unsigned char * volatile piAddr; とするとアドレスが最適化されないという意味になります。
    基本的にはアドレスの指す先が最適化されないというのが一般的ではないかと思います。 [引用終]

    この人が「最適化はコンパイラが独自に行いますのでこれ(注:実際の最適化具体例)が確実に行われるかは判りません」と繰り返し書かれていますが、今回の元々の話のように割り込みルーチン内でポインタ変数(例えばこの人のpiAddr)を変更するという場合でも、最適化能力の低いコンパイラ、あるいはそもそも処理内容によっては、volatile unsigned char *piAddr;と書いてもトラブルを起こさなくなることがあると思います。極端な話、volatileを付けなくてもトラブルを起こさない場合もありますし。
    でも、組み込みに不慣れな人が書いたソースで割り込みルーチン内で変更される変数にvolatileが付いてなければ付けるように話をされると思いますし、もしその人が付けても付けなくてもコンパイラの生成コードが変わらないことに気付いて反論してきても、機能追加でソースを変更したら、あるいはコンパイラのバージョンが上がったら、もしくは他のマイコンの他のコンパイラでコンパイルすることになったら、トラブルを起こすかも知れないので付けるようにと、話をされると思います。
    volatileを付ける位置のこと考える時に、この例え話のシチュエーションも考えてみると、話のポイントがくっきりして来ないでしょうか?

  • NoMaY さんの初めの書き込みで、指摘している問題点がよく分からなかった。
    volatile を行頭に付けておけばその変数に関する最適化を抑制すると思っていました。
    しかし今回の議論で、ポインタが絡むと volatile の位置によって意味が変ると言うのが分かりました。
    インターネットで volatile を調べてもポインタが絡んだときの事が書いて無いから、ハナタカに入る例じゃないかな。
    だから、コード生成ツールを作った人も気付かなかったのでしょう。
    これが原因でコンパイル結果が意図したように行われなかったら、原因究明に苦労するでしょう。
    ひとつ勉強になりました。
  • "volatile ポインタ"で検索すると、いろいろと出てきますよ。
  • Higetaka さん、有難う。

    >"volatile ポインタ"で検索すると、いろいろと出てきますよ。

    ああ、そうか。そのキーワードにすればいいんですね。簡単な事だけど、思い付かなかった。
    調べると、volatile の位置の違いで引っ掛かった人が他にもいましたね。