#!/bin/sh # Print the gcc cpu specific options tailored for the current CPU # License: LGPLv2 # Author: # http://www.pixelbeat.org/ # Notes: # This script currently supports Linux,FreeBSD,Cygwin # This script is x86 (32 bit) specific # It should work on any gcc >= 2.95 at least # It only returns CPU specific options. You probably also want -03 etc. # Changes: # V0.1, 12 Mar 2003, Initial release # V0.2, 01 Jun 2005, Added support for 3.2>=gcc<=4.0 # V0.3, 03 Jun 2005, Added support for pentium-m # V0.4, 03 Jun 2005, Fix silly bugs # V0.5, 07 Jun 2005, Clarify/Simplify confusing floating point expr usage # Print warning when CPU only supported on a newer gcc # V0.6, 15 Dec 2006, Added support for Intel Core and Core 2 processors # Added support for 4.1>=gcc<=4.3 # Added support for gcc -msse3 option # Added support for new gcc -march=native option # V0.7, 18 Dec 2006, Changes from Conor McDermottroe # Added support for FreeBSD # Remove bash specific constructs # Better error handling # V0.8, 19 Dec 2006, Give warnings and 32 bit -march on 64 bit platforms. # Previously it just gave an invalid blank -march. # Reported and tested by Ewan Oughton. # V0.9, 30 Apr 2007, Give error if compiler not present. # Warn about rather than default to -march=native option. # V0.92, 08 Nov 2007, Change from Krzysztof Jankowski to support Cygwin. # Added support for AMD family 10 processors. # Add support for gcc -msse4 & -msse5 options. # Use "prescott" rather than "pentium4" for all # models >= 3 in intel family 15, not just model 3. # V0.93, 13 Nov 2007, Oops, actually not all intel family 15, model >= 3 # are prescotts. Use the sse3 flag to distinguish. # V0.94, 31 Dec 2007, Oops, actually all intel family 15, model >= 3 # are prescotts. This was indicated by Adam Drzewiecki. # I was confused by a bug in older linux kernels where pni # was not reported for my intel "F41" processor at least. # V0.95, 18 Jan 2008, Changes from Conor McDermottroe # Support for Mac OS X # Support for FreeBSD base system # V0.96, 17 Dec 2008, Following a report from Alfredo Pons, add support # for newer intel core2 processors (models 23,26,29,...) # by assuming models >= 15 are core2. # Report details of unrecognised CPUs. # V0.97, 19 Dec 2008, Use prescott for Intel Atom (model 28). # Ensure all errors are output to stderr. # V0.98, 24 Feb 2009, Actually Intel Atom (model 28) is core2 ISA compliant. # It's an in-order core (like i586) so mtune as such. # V0.99, 30 Apr 2009, Intel Atom (model 28) is getting a corresponding "atom" # option in GCC 4.5 # V0.99.3, 11 Aug 2009, Support for AMD Geode LX processor. # V0.99.4, 24 Oct 2009, Following a report from Maxime de Roucy, add support # for AMD family 17 (griffin). # V0.99.14, 16 Jul 2015 # http://github.com/pixelb/scripts/commits/master/scripts/gcccpuopt if test $1 = "--version" { echo "0.99.14" && exit } # This table shows when -march options were introduced into _official_ gcc releases. # Note there are vendor deviations that complicate this. # For e.g. Red Hat introduced the prescott option in 3.3-13. # gcc-2.95 = i386, i486, i586,pentium, i686,pentiumpro, k6 # gcc-3.0 += athlon # gcc-3.1 += pentium-mmx, pentium2, pentium3, pentium4, k6-2, k6-3, athlon-{tbird, 4,xp,mp} # gcc-3.3 += winchip-c6, winchip2, c3 # gcc-3.4.0 += k8,opteron,athlon64,athlon-fx, c3-2 # gcc-3.4.1 += pentium-m, pentium3m, pentium4m, prescott, nocona # gcc-4.3 += core2, amdfam10, geode # gcc-4.5 += atom # gcc-4.6 += corei7, corei7-avx, bdver1, btver1 # gcc-4.7 += core-avx-i, core-avx2, bdver2 # gcc-4.8 += btver2 # gcc-4.9 += b[td]ver[34], broadwell, silvermont # gcc-5.1 += knl test -z $CC && setglobal CC = 'gcc' proc try_gcc_options { $CC $ifsjoin(Argv) -S -o /dev/null -xc /dev/null >/dev/null !2 > !1 } if ! try_gcc_options { echo "Error: Couldn't execute your compiler ($CC)" > !2 exit 1 } if try_gcc_options -march=native { echo "Warning: Your compiler supports the -march=native option which you may prefer" > !2 #gcc -march=native --verbose -xc /dev/null 2>&1 | sed -n 's|.*/dev/null \(-march.*-mtune[^ ]*\).*|\1|p' >&2 } if ! try_gcc_options -march=i386 { if ! try_gcc_options -m32 -march=i386 { echo "Error: This script only supports 32 bit x86 architectures" > !2 exit 1 } else { echo "Warning: The optimum *32 bit* architecture is reported" > !2 setglobal m32 = '"-m32 '" } } proc try_line { setglobal skip = '0' for arch in [$1] { if try_gcc_options $m32 -march=$arch { echo $arch return } elif test $skip = "0" && test $arch != "native" { setglobal skip = '1' echo "Warning: Newer versions of GCC better support your CPU with -march=$arch" > !2 } } return 1 } proc read_cpu_data_linux { setglobal IFS = '":'" while read name value { unset IFS setglobal name = $[echo $name] #strip spaces setglobal value = $[echo $value] #strip spaces if test $name = "vendor_id" { setglobal value = $[echo $value | sed 's/\([^ ]*\).*/\1/] #take first word } setglobal IFS = '":'" if test $name = "vendor_id" { setglobal vendor_id = $value } elif test $name = "cpu family" { setglobal cpu_family = $value } elif test $name = "model" { setglobal cpu_model = $value } elif test $name = "flags" { setglobal flags = $value break #flags last so break early } } < /proc/cpuinfo unset IFS } proc read_cpu_data_freebsd { local _line _cpu_id if test ! -r /var/run/dmesg.boot { echo "Error: /var/run/dmesg.boot does not exist!" > !2 exit 1; } setglobal IFS = '" '" for _line in [$[grep -A2 '^CPU: ' /var/run/dmesg.boot]] { if test -n $[echo $_line | grep '^ Origin = ] { setglobal vendor_id = $[echo $_line | sed -e 's/^ Origin = .//' -e 's/[^A-Za-z0-9].*$//] setglobal _cpu_id = $[echo $_line | sed -e 's/^.*Id = //' -e 's/ .*$//' -e 'y/abcdef/ABCDEF/] setglobal cpu_family = $shExpr(' ($_cpu_id & 0xF0F) >> 8 ') #FreeBSD 5.0 sh doesn't support 0x setglobal cpu_model = $shExpr(' (($_cpu_id & 0xF0) >> 4) + (($_cpu_id & 0xF0000) >> 12) ') } if test -n $[echo $_line | grep '^ Features=] { setglobal flags = $[echo $_line | sed -e 's/^.*.*//' -e 's/,/ /g' | tr 'A-Z' 'a-z] } } unset IFS } proc read_cpu_data_darwin { setglobal vendor_id = $[/usr/sbin/sysctl -n machdep.cpu.vendor] setglobal cpu_family = $[/usr/sbin/sysctl -n machdep.cpu.family] setglobal cpu_model = $[/usr/sbin/sysctl -n machdep.cpu.model] setglobal flags = $[/usr/sbin/sysctl -n machdep.cpu.features | tr 'A-Z' 'a-z] } proc read_cpu_data { # Default values setglobal vendor_id = '"NotFound'" setglobal cpu_family = '"-1'" setglobal cpu_model = '"-1'" setglobal flags = ''"" match $[uname] { with Linux|CYGWIN* read_cpu_data_linux with FreeBSD read_cpu_data_freebsd with Darwin read_cpu_data_darwin with * echo "Error: $[uname] is not a supported operating system" > !2 exit 1 } } read_cpu_data if test $vendor_id = "AuthenticAMD" { if test $cpu_family -eq 4 { setglobal _CFLAGS = '"-march=i486'" } elif test $cpu_family -eq 5 { if test $cpu_model -lt 4 { setglobal _CFLAGS = '"-march=pentium'" } elif test '(' $cpu_model -eq 6 ')' -o '(' $cpu_model -eq 7 ')' { setglobal _CFLAGS = '"-march=k6'" } elif test '(' $cpu_model -eq 8 ')' -o '(' $cpu_model -eq 12 ')' { setglobal line = '"k6-2 k6'" } elif test '(' $cpu_model -eq 9 ')' -o '(' $cpu_model -eq 13 ')' { setglobal line = '"k6-3 k6-2 k6'" } elif test $cpu_model -eq 10 { #geode LX setglobal line = '"geode k6-2 k6'" #The LX supports 3dnowext in addition to the k6-2 instructions, #however gcc doesn't support explicitly selecting that. } } elif test $cpu_family -eq 6 { if test $cpu_model -le 3 { setglobal line = '"athlon k6-3 k6-2 k6'" } elif test $cpu_model -eq 4 { setglobal line = '"athlon-tbird athlon k6-3 k6-2 k6'" } elif test $cpu_model -ge 6 { #athlon-{4,xp,mp} (also geode NX) setglobal line = '"athlon-4 athlon k6-3 k6-2 k6'" } } elif test $cpu_family -eq 15 { #k8,opteron,athlon64,athlon-fx setglobal line = '"k8 athlon-4 athlon k6-3 k6-2 k6'" } elif test $cpu_family -eq 16 || #barcelona,amdfam10 test $cpu_family -eq 17 || #griffin test $cpu_family -eq 18 { #llano setglobal line = '"amdfam10 k8 athlon-4 athlon k6-3 k6-2 k6'" } elif test $cpu_family -eq 20 { #bobcat setglobal line = '"btver1 amdfam10 k8 athlon-4 athlon k6-3 k6-2 k6'" } elif test $cpu_family -eq 21 { #bulldozer if echo $flags | grep -q bmi { #piledriver setglobal line = '"bdver2 bdver1 btver1 amdfam10 k8 athlon-4 athlon k6-3 k6-2 k6'" } else { setglobal line = '"bdver1 btver1 amdfam10 k8 athlon-4 athlon k6-3 k6-2 k6'" } } elif test $cpu_family -eq 22 { #jaguar setglobal line = '"btver2 btver1 amdfam10 k8 athlon-4 athlon k6-3 k6-2 k6'" } } elif test $vendor_id = "CentaurHauls" { if test $cpu_family -eq 5 { if test $cpu_model -eq 4 { setglobal line = '"winchip-c6 pentium'" } elif test $cpu_model -eq 8 { setglobal line = '"winchip2 winchip-c6 pentium'" } elif test $cpu_model -ge 9 { setglobal line = '"winchip2 winchip-c6 pentium'" #actually winchip3 but gcc doesn't support this currently } } elif test $cpu_family -eq 6 { if echo $flags | grep -q cmov { setglobal fallback = 'pentiumpro' } else { setglobal fallback = 'pentium' #gcc incorrectly assumes i686 always has cmov } if test $cpu_model -eq 6 { setglobal _CFLAGS = '"-march=pentium'" # ? Cyrix 3 (samuel) } elif test $cpu_model -eq 7 || test $cpu_model -eq 8 { setglobal line = ""c3 winchip2 winchip-c6 $fallback"" } elif test $cpu_model -ge 9 { setglobal line = ""c3-2 c3 winchip2 winchip-c6 $fallback"" } } } elif test $vendor_id = "GenuineIntel" { if test $cpu_family -eq 3 { setglobal _CFLAGS = '"-march=i386'" } elif test $cpu_family -eq 4 { setglobal _CFLAGS = '"-march=i486'" } elif test $cpu_family -eq 5 { if test $cpu_model -ne 4 { setglobal _CFLAGS = '"-march=pentium'" } else { setglobal line = '"pentium-mmx pentium'" #No overlap with other vendors } } elif test $cpu_family -eq 6 { if test '(' $cpu_model -eq 0 ')' -o '(' $cpu_model -eq 1 ')' { setglobal _CFLAGS = '"-march=pentiumpro'" } elif test '(' $cpu_model -ge 2 ')' -a '(' $cpu_model -le 6 ')' { #4=TM5600 at least setglobal line = '"pentium2 pentiumpro pentium-mmx pentium i486 i386'" if test '(' $cpu_model -eq 2 ')' { #qemu generic echo "\ Warning: Unspecified QEMU CPU model. Please consider upgrading QEMU or configuring it to use a specific model." > !2 } } elif test '(' $cpu_model -eq 9 ')' -o '(' $cpu_model -eq 13 ')' { #centrino setglobal line = '"pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386'" } elif test '(' $cpu_model -eq 14 ')' { #Core setglobal line = '"prescott pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386'" } elif test $cpu_model -eq 28 || # pine test $cpu_model -eq 38 || # oak test $cpu_model -eq 54 { # cedar setglobal line = '"atom core2 pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386'" } elif test $cpu_model -eq 55 || # Bay trail test $cpu_model -eq 74 || # Merrifield test $cpu_model -eq 77 || # Avoton test $cpu_model -eq 90 || # Moorefield test $cpu_model -eq 93 { setglobal line = '"silvermont atom core2 pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386'" } elif test $cpu_model -eq 26 || test $cpu_model -eq 30 || test $cpu_model -eq 31 || test $cpu_model -eq 46 || # ^ Nehalem ^ test $cpu_model -eq 37 || test $cpu_model -eq 44 || test $cpu_model -eq 47 { # ^ Westmere ^ setglobal line = '"corei7 core2 pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386'" } elif test $cpu_model -eq 42 || #Sandy Bridge test $cpu_model -eq 45 { #Sandy Bridge E setglobal line = '"corei7-avx corei7 core2 pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386'" } elif test $cpu_model -eq 58 || #Ivy Bridge test $cpu_model -eq 62 { #Ivy Bridge E setglobal line = '"core-avx-i corei7-avx corei7 core2 pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386'" } elif test $cpu_model -eq 60 || #Haswell test $cpu_model -eq 63 || #Haswell E test $cpu_model -eq 69 || #Haswell U test $cpu_model -eq 70 { #Haswell Crystalwell setglobal line = '"core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386'" } elif test $cpu_model -eq 61 || #Broadwell test $cpu_model -eq 71 || test $cpu_model -eq 79 || test $cpu_model -eq 86 { setglobal line = '"broadwell core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386'" } elif test $cpu_model -eq 87 { #Knight's landing (haswell compat) setglobal line = '"knl core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386'" } elif test $cpu_model -eq 15 || # ^ Merom ^ test $cpu_model -eq 22 || # ^ Conroe-L ^ test $cpu_model -eq 23 || test $cpu_model -eq 29 { # ^ Penryn ^ setglobal line = '"core2 pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386'" } elif test '(' $cpu_model -ge 7 ')' -a '(' $cpu_model -le 11 ')' { setglobal line = '"pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386'" } } elif test $cpu_family -eq 15 { setglobal line = '"pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386'" if test $cpu_model -ge 3 { setglobal line = ""prescott $line"" } } } elif test $vendor_id = "Geode" { #by NSC if test $cpu_family -eq 5 { if test '(' $cpu_model -eq 4 ')' -o '(' $cpu_model -eq 9 ')' { # Note both models 4 and 9 have cmov. # In addition, model 9 has cxmmx. # Note also, the "geode" gcc arch is for newer AMD geode cores # and is not appropriate for this older core. setglobal line = '"pentium-mmx pentium'" } } } if test '(' -z $_CFLAGS ')' -a '(' -z $line ')' { echo "\ Unrecognised CPU. Please email the following to: P@draigBrady.com Vendor:$vendor_id family:$cpu_family model:$cpu_model flags:$flags" > !2 exit 1 } test -z $_CFLAGS && setglobal _CFLAGS = ""-march=$[try_line $line]"" #The Atom CPU supports the full core2 instruction set, #but it's an in-order core, the last one of those being the i586. #Therefore if gcc hasn't explicit support for the Atom, #tune it for the i586 architecture. if ! echo $_CFLAGS | grep -q "atom" { #gcc hasn't specific Atom support if echo $line | grep -q "core2" { #atom ISA line if test $cpu_model -eq 28 { #atom if echo $_CFLAGS | grep -E -q "(core2|pentium[^ ])" { #gcc chose out of order arch setglobal _CFLAGS = ""$_CFLAGS -mtune=pentium"" #tune for last in-order core } } } } #SSE is not used for floating point by default in gcc 32 bit #so turn that on here. if echo $flags | grep -q "sse" { if try_gcc_options "-mfpmath=sse" { #gcc >= 3.1 setglobal _CFLAGS = ""$_CFLAGS -mfpmath=sse"" } } #The SSE options are mostly selected automatically #when a particular march option is selected. #There are a few exceptions unfortunately, which we handle here. #Note the sse instruction lines are: # intel: [sse4.2] [sse4.1] ssse3 sse3 sse2 sse ... # amd: [sse5] sse4a [sse3] sse2 sse ... # The bracketed ones are only available on some cpus # in a particular family and so need to be added explicitly. if echo $_CFLAGS | grep -q "amdfam10" { if echo $flags | grep -q "sse5" { if try_gcc_options "-msse5" { #gcc >= 4.3 setglobal _CFLAGS = ""$_CFLAGS -msse5"" } } } elif echo $_CFLAGS | grep -E -q "(k8|c3-2)" { if echo $flags | grep -E -q "(sse3|pni)" { if try_gcc_options "-msse3" { #gcc >= 3.3.3 setglobal _CFLAGS = ""$_CFLAGS -msse3"" } } } elif echo $_CFLAGS | grep -q "core2" { if echo $flags | grep -q "sse4_2" { if try_gcc_options "-msse4" { #gcc >= 4.3 setglobal _CFLAGS = ""$_CFLAGS -msse4"" } } elif echo $flags | grep -q "sse4_1" { if try_gcc_options "-msse4.1" { #gcc >= 4.3 setglobal _CFLAGS = ""$_CFLAGS -msse4.1"" } } } echo "$m32$_CFLAGS"