GCC's "-march=native" Option

どうも.先程 #GentooInstallBattle を始めました.

ところで,gccの-march=nativeオプションですが,CPUアーキテクチャに合わせた最適化をするという意味ですが,それがどんな感じに展開されてるのか気になり調べてみました.

Version of GCC

$ gcc --version
gcc (GCC) 7.2.1 20171128
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

man of GCC(L:18896)

       -march=cpu-type
           Generate instructions for the machine type cpu-type.  In contrast to
           -mtune=cpu-type, which merely tunes the generated code for the specified cpu-
           type, -march=cpu-type allows GCC to generate code that may not run at all on
           processors other than the one indicated.  Specifying -march=cpu-type implies
           -mtune=cpu-type.

           The choices for cpu-type are:

           native
               This selects the CPU to generate code for at compilation time by
               determining the processor type of the compiling machine.  Using
               -march=native enables all instruction subsets supported by the local
               machine (hence the result might not run on different machines).  Using
               -mtune=native produces code optimized for the local machine under the
               constraints of the selected instruction set.

gcc-march=native オプションを使用するとビルドするコンピューターのCPUでサポートされてるすべてのinstruction subsetsを使用するようにしてくれるようです.

-march=native の展開

-E -vオプションを使えば簡単に出来ました.

-E

       -E  Stop after the preprocessing stage; do not run the compiler proper.  The output
           is in the form of preprocessed source code, which is sent to the standard
           output.

           Input files that don't require preprocessing are ignored.

-v

       -v  Print (on standard error output) the commands executed to run the stages of
           compilation.  Also print the version number of the compiler driver program and
           of the preprocessor and the compiler proper.

ということでどんな結果が出るのか見てみましょう.

$ echo | gcc -E -v -march=native - 2>&1 | grep cc1
 /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.1/cc1 -E -quiet -v - -march=haswell -mmmx -mno-3dnow -msse -msse2 -msse3 -mssse3 -mno-sse4a -mcx16 -msahf -mmovbe -maes -mno-sha -mpclmul -mpopcnt -mabm -mno-lwp -mfma -mno-fma4 -mno-xop -mbmi -mno-sgx -mbmi2 -mno-tbm -mavx -mavx2 -msse4.2 -msse4.1 -mlzcnt -mno-rtm -mno-hle -mrdrnd -mf16c -mfsgsbase -mno-rdseed -mno-prfchw -mno-adx -mfxsr -mxsave -mxsaveopt -mno-avx512f -mno-avx512er -mno-avx512cd -mno-avx512pf -mno-prefetchwt1 -mno-clflushopt -mno-xsavec -mno-xsaves -mno-avx512dq -mno-avx512bw -mno-avx512vl -mno-avx512ifma -mno-avx512vbmi -mno-avx5124fmaps -mno-avx5124vnniw -mno-clwb -mno-mwaitx -mno-clzero -mno-pku -mno-rdpid --param l1-cache-size=32 --param l1-cache-line-size=64 --param l2-cache-size=6144 -mtune=haswell

こちらが平常時になります.

$ echo | gcc -E -v  - 2>&1 | grep cc1
 /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.1/cc1 -E -quiet -v - -mtune=generic -march=x86-64

上の2つを比較してあげると -march=native でどのオプションが追加されたかがわかります.

-march=haswell -mmmx -mno-3dnow -msse -msse2 -msse3 -mssse3 -mno-sse4a -mcx16 -msahf -mmovbe -maes -mno-sha -mpclmul -mpopcnt -mabm -mno-lwp -mfma -mno-fma4 -mno-xop -mbmi -mno-sgx -mbmi2 -mno-tbm -mavx -mavx2 -msse4.2 -msse4.1 -mlzcnt -mno-rtm -mno-hle -mrdrnd -mf16c -mfsgsbase -mno-rdseed -mno-prfchw -mno-adx -mfxsr -mxsave -mxsaveopt -mno-avx512f -mno-avx512er -mno-avx512cd -mno-avx512pf -mno-prefetchwt1 -mno-clflushopt -mno-xsavec -mno-xsaves -mno-avx512dq -mno-avx512bw -mno-avx512vl -mno-avx512ifma -mno-avx512vbmi -mno-avx5124fmaps -mno-avx5124vnniw -mno-clwb -mno-mwaitx -mno-clzero -mno-pku -mno-rdpid --param l1-cache-size=32 --param l1-cache-line-size=64 --param l2-cache-size=6144 -mtune=haswell

ちょうど自分の環境ではこのようになります.

これだけでは面白くないのでこのオプションを生成してる部分のソースを見に行きましょう.

github.com

これの381行目 const char *host_detect_local_cpu (int argc, const char **argv) で見れます.かなり気合のオプション生成をしてますので見てみると楽しいです. AArch64では,実は内部で f = fopen ("/proc/cpuinfo", "r"); をやって /cpu/procinfo を読みに行ってて,それをゴニョゴニョしてオプションを生成してました.

gcc/config/${arch}/driver-${arch}.c というような規則性があるようですので,他のアーキテクチャのオプション生成もどうやってるか見て楽しむことができそうなので,ぜひ皆さん見てみてください.