2017/5/11 4:30追記。皆様のお陰で一応解決しました。ご協力いただいた皆様、ありがとうございました。
一言で言うとgccの挙動がよくわからん。誰か助けて欲しい。
以下の作業はMSYS2上のgccでやっている。
1%でも実行速度が速いほうが良いので、まず、最適化オプションとして、-fltoを指定したい。この最適化オプションは、コンパイラ(CFLAGS)とリンカー(LDFLAGS)との両方につけないといけないらしい。
問題点1)
ところが、CFLAGSに-flto、-Ofastの二つを指定すると生成された実行ファイルを実行した途端にセグフォになる。空っぽのプロジェクト(空のmain関数だけのもの)でも同様にセグフォ。-flto、-O2にしても同様。-fltoをつけるときは、-O2を指定してはいけないのか?-O2をつけなければセグフォにはならない。
問題点2)
仕方ないので、-O2をつけるのはやめて、CFLAGSとLDFLAGSの両方に-fltoをつけてコンパイル。やねうら王でこれをやるとやはりセグフォ。魔女のMakefileを見たところ、あちらはCFLAGSには-fltoがついておらず(LDFLAGSにはついている)、-fltoをつけてコンパイルするとセグフォ。
2017/5/11 0:00追記 → 平岡さん : Aperyでは「MinGW で PGO ビルドが失敗する問題への対処として -flto オプションを外す。」 などとしている(´・_・`)
とのこと。Linux上なら問題ないようなのでMinGW固有の問題かも…。
問題点3)
各CPU用の実行ファイルを用意する方法がわからない。魔女のMakefileでSSE4.1用のビルドは以下のようになっている。
CFLAGS += -march=native
(中略)
sse41: $(MAKE) CFLAGS=’$(CFLAGS) -DNDEBUG -DHAVE_SSE4 -msse4.1′ LDFLAGS=’$(LDFLAGS) -flto’ $(TARGET)
やねうら王でもだいたい同様に指定しているのだが、これだとコンパイルするマシンに左右されるはずで、こうやって生成された実行ファイルはSSE4.1までしかサポートしていないPCで実行できないようだ。
2017/5/11 0:00追記 → -march=nativeはつけると駄目らしい。具体的なCPU名を指定したときにコンパイルエラーになるのは、また別の問題らしい。gccでは_blsr_u64()を使わないことにした。
2017/5/11 1:30追記 → -march=nativeを外すと各CPU向けの実行ファイル、無事生成されているようでした。(32bit OS向け以外)
問題点4)
よくわからないが、では具体的なCPUも指定しようと以下のようにした。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
avx2: $(MAKE) CFLAGS='$(CFLAGS) -DNDEBUG -DUSE_MAKEFILE -D$(YANEURAOU_EDITION) -DUSE_AVX2 -msse4.2 -mbmi2 -mavx2 -march=corei7-avx' LDFLAGS='$(LDFLAGS) -flto' $(TARGET) sse42: $(MAKE) CFLAGS='$(CFLAGS) -DNDEBUG -DUSE_MAKEFILE -D$(YANEURAOU_EDITION) -DUSE_SSE42 -msse4.2 -march=corei7' LDFLAGS='$(LDFLAGS) -flto' $(TARGET) sse41: $(MAKE) CFLAGS='$(CFLAGS) -DNDEBUG -DUSE_MAKEFILE -D$(YANEURAOU_EDITION) -DUSE_SSE41 -msse4.1 -march=core2' LDFLAGS='$(LDFLAGS) -flto' $(TARGET) sse2: $(MAKE) CFLAGS='$(CFLAGS) -DNDEBUG -DUSE_MAKEFILE -D$(YANEURAOU_EDITION) -DUSE_SSE2 -msse2 -march=core2' LDFLAGS='$(LDFLAGS) -flto' $(TARGET) nosse: $(MAKE) CFLAGS='$(CFLAGS) -DNDEBUG -DUSE_MAKEFILE -D$(YANEURAOU_EDITION) -DNO_SSE -march=pentium3' LDFLAGS='$(LDFLAGS) -flto' $(TARGET) |
ところが、今度はコンパイルが通らない。
bitop.h
#define FORCE_INLINE __attribute__((always_inline)) inline (中略) #define BLSR(x) _blsr_u64(x) このBLSRを使ってあるところがinline化できないというエラーのようなのだが、そもそもCPU名を指定しないときは何故コンパイルが通っていたのだ?
2017/5/11 1:30追記 → 具体的なCPU名を指定するとこうなるようです。またgcc環境では_blsr_u64(x)は使わないようにしました。これなら具体的なCPU名を指定してあっても大丈夫なようです。
問題点5)
x86(32bit)用のコンパイル方法がわからない。SSEなし(nosse)用の実行ファイルは、x86用のつもりなのだが、どうやってx86用にすればいいのかわからない。
2017/5/11 0:00追記 → 本記事のコメント欄でいただいたコメントによると32bit用のコンパイル環境が別に必要そうなのだが…。
2017/5/11 1:00追記 → -m32オプション、mingw64では無視されるというのを知りませんでした。mingw32でコンパイル環境構築しました。
2017/5/11 4:30追記 → Makefileを修正して、無事32bit用の実行ファイルが生成できました。
問題点6)
alignasの指定があるとARM用のコンパイルでコンパイルエラーになるらしいのだが、これ必要のない時にはつけないほうが良いのか?
2017/5/11 0:00追記 → あってもいいらしい。
特にgccは詳しくないんですが、問題点5だけぐぐったらわかったのでコメントしておきます。
まず、MySYS MinGW-64だと-m32オプションはさくっと無視されるようで、どうしてもMinGW-64で32bitバイナリを作りたい場合はMinGW-64(32bit環境用)というよくわからないものがあるらしいのでそっちを使えばいいそうです。また、代替としてMinGW-64ではなくTDM-GCCというものがあるらしいので、そちらを使うと-m32オプションはしっかり効くそうです。
ありがとうございます。バッチファイルで一括して作りたいので、x86用だけMinGW-64から変更するわけにもいかず…。うーむ..
https://ci.appveyor.com/project/YasushiAbe/yaneuraou/build/job/1gno8847vrde8rh8
(凝りずに)AppVeyorで32bitのビルドをしてみましたが、
learn/evaluate_kppt_learn.cpp:380:39: error: size of array ‘kpp_w_’ is too large
で失敗してしまいました。
32bit環境ですと機械学習時に必要となる配列が大きいので、EVAL_LEARNはオフにしないといけないですね…。試しにextra/config.hの末尾で#undef EVAL_LEARNとしてみてもらえますでしょうか。
https://ci.appveyor.com/project/YasushiAbe/yaneuraou/build/job/x761rg4qc7wcvhk0
コンパイルできたようです
いま手元にwindowsマシンがないので動作確認はできてないです。
名前がまぎらわしいんですけど、mingw-w64の32bitコンパイラ、という扱いなんですよね。
http://qiita.com/spiegel-im-spiegel/items/ba4e8d2418bdfe0c8049#32bit-%E7%89%88-gcc-%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB
ご確認、ありがとうございます。私のほうの手元でも32bit用のmingw起動して、
pacman -S mingw-w64-i686-toolchain
しました。コンパイルエラーがあってまだコンパイル通ってないですが。しかしまぁ、32bit用のコンパイルのために32bit用のmingwを起動するのは面倒ですね…。
https://github.com/Yasushi/YaneuraOu/blob/e4e9f7ba79c56ec4e70218f5c24918a97c0fd23a/appveyor.yml#L19-L28
一応、Path通すだけでもいけますので、バッチでやるんならこれが楽でしょうか。
おお、なんというhack。ありがとうございます。
それとは別に、私のほうでは、まだコンパイル通ってなくて __int128が
> C:/msys64/mingw32/i686-w64-mingw32/include/_mingw.h:241:13: error: expected unqualified-id before ‘__int128’
typedef int __int128 __attribute__ ((__mode__ (TI)));
だとかで…(´ω`)
https://github.com/Yasushi/YaneuraOu/commit/99bf636cc42aeb3b082d53a3a27166310a00b903
__int128のエラーはこれで消えました。
gcc -dM -E – <NUL: で確認したところ、i686のgccは_WIN32のみ、x86_64のgccは_WIN32、_WIN64がdefineされるので大丈夫なはずですがどうでしょう。
なるほど!_WIN64をdefineしてたので__int128がなかったんですね…。ありがとうございます。なんとかいけそうです!
おかげさまでmingw32では無事32bit用の実行ファイルが作れました。mingw64のほうで
$ export Path=C:/msys64/mingw32/bin;$PATH
$ mingw32-make -j8 nosse YANEURAOU_EDITION=YANEURAOU_2017_EARLY_ENGINE
してpathを変更してみたものの、__int128のところでコンパイルエラーになったので32bit用のファイルが読み込めてないんですかね…。うーむ..。こうして見るとAppVeyor優秀ですね…。
あ、すいません。説明不足でした。
mingw64.exe等で起動したbash上ではインクルードファイルのサーチパス等が設定されている可能性があって、Pathだけでは不十分なんです。
逆に、cmd.exe等からだとgccのコンパイル時にデフォルトで設定されたサーチパスが使われるのでPathだけでいけるはずです(appveyor.ymlではPowerShellを使いました)
なるほど、そうなんですね!ありがとうございます。
問題点3
>CFLAGS += -march=native
これが不要です。
nativeつけてるとコンパイルした環境に最適化されます。
問題点6
androidでの話ですが、alignasはamr64-v8a,STLがc++_static,TOOLCHAINが4.9だと問題ないです。
androidはARMのABIがarmeabi,armeabi-v7a,arm64-v8aと3種類あって、STLの種類やツールチェインのバージョンなんかも複数あるので、もしかするとダメなパターンがあるのかも。
> nativeつけてるとコンパイルした環境に最適化されます。
やはりそうですよね…。それで、alignasのほうは、つけておいても大丈夫ということですかね。色々ありがとうございます。
twitterでいただいた情報。問題4のほうは、どう解決すべきなんでしょう…。
https://twitter.com/replicorn/status/862321736326430722
> 問題4はマシン指定することで、組み込み関数_blsr_u64を使うようになったことがエラーの原因かもしれません。
> 問題5は、ここが参考になりそうです。
> http://blog.kmckk.com/archives/1576355.html
→ gcc環境では _blsr_u64() 使わないようにしました。(これでいいのかな?)
gccには、関係ありませんが、iccでやると、ちょっとは性能上がるのでしょうか。(金払う価値あり?)
その昔、体験版で試したらVC++とさほど変わりませんでしたけども。いまはどうだかわかりません…。体験版で誰か試してもらえればと…。