末代鯖の参加を鯖の物理距離を近くしてお待ちしています。(フランス -> 東京)
ニコニコをCoqで証明してみた / Yosh さん - ニコナレ https://niconare.nicovideo.jp/watch/kn3390
Undefined
Behavior
Works
例のようなコードそのものを書く人はあまりいないけれど、あれこれやっているうちに事実上これと同じコードになってアというのはありがち
http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_14.html の例はこれですね。
void contains_null_check(int *P) {
int dead = *P;
if (P == 0) return;
*P = 4;
}
このコードに「不要なNULLチェックを削除する」最適化を行うと、int dead = *P;という(PがNULLだとその時点で止まる)文があることから、if (P == 0) return;に到達する場合はチェックせずともNULLでないことは明らかなので if (P == 0) return;が消えます。
その後で「使われていない変数を削除する」最適化を行うとint dead = *P;も消えます。
void contains_null_check(int *P) {
*P = 4;
}
結果、NULLチェックがあったはずのコードからNULLチェックが消えます。何が悪かったかというと最適化の順番……ではなく、int dead = *P;が悪い
以前ここに貼ったけど、GCCとClangで最適化パスの適用順序が違うので、さっきの記事の2回目 http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_14.html に登場するある順番で最適化するとNULLチェックが吹っ飛ぶけど別の順番で最適化するとNULLチェックが残るという例は実際に起きる
LLVM Project Blog: What Every C Programmer Should Know About Undefined Behavior #1/3 http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
最初の話については(以前も紹介したけど)この3回シリーズを読むと良いよ
本の虫: なんでGCCはa*a*a*a*a*a を (a*a*a)*(a*a*a) に最適化できないの?っと https://cpplover.blogspot.com/2014/03/gccaaaaaa-aaaaaa.html
まさにこれの話ぽそう?
最初の話についてはコンパイラのバージョンを上げると壊れたり、コンパイラを変える(GCCからClangとか)と壊れたり、最適化レベルを上げると壊れたり、コンパイラのバージョンも最適化レベルも同じでも出力コードのCPUアーキテクチャが違うとアーキテクチャ依存の最適化パスが切り替わって壊れたり、ありとあらゆるタイミングで壊れる可能性があるのでUBはやめようねという話
最後の話についてもう少し話すと、数学の授業で習うa * (b + c) = a * b + a * cのような恒等式で表される式変形がプログラミング言語が提供している整数型や浮動小数点数型の式でも必ず成り立つとは限らないのですが、-ffast-mathのようなオプションはあたかも必ず成り立つかのように式変形をして計算を高速化する代わりに結果が元の式と別の値になったりならなかったりします
コードに問題がある場合もある(たとえば、世の中のC言語のコードにはしばしば言語仕様上動くことが保証されていない記述が含まれている)し、最適化にバグがある場合もあるし、強い最適化の中には言語仕様上許されていないコード変換を行うもの(GCCの-ffast-mathなど)もあって、これを使うと言語仕様によればある結果が確実に得られるコードも別の結果を得るようになって壊れることがある
そういえばどうして最適化を強くすると動かなくなるんだろう あれは実際コードがわるいものなの それとも最適化側がわるいものなの
ICARUS Neutrino Detector Installation at Fermilab https://youtu.be/1Qmr7WEKy-Q
ロシア宇宙主義 - Wikipedia https://ja.wikipedia.org/wiki/%E3%83%AD%E3%82%B7%E3%82%A2%E5%AE%87%E5%AE%99%E4%B8%BB%E7%BE%A9