Bug 69471 - "-march=native" unintentionally breaks further -march/-mtune flags
Summary: "-march=native" unintentionally breaks further -march/-mtune flags
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: driver (show other bugs)
Version: 5.3.0
: P3 normal
Target Milestone: 9.3
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 42444 (view as bug list)
Depends on:
Blocks:
 
Reported: 2016-01-25 17:29 UTC by wavexx
Modified: 2021-12-20 00:46 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-02-08 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description wavexx 2016-01-25 17:29:14 UTC
On a haswell host, the following:

gcc -march=native -march=opteron

or

gcc -march=opteron -march=native

both emit code which is illegal for the opteron ISA.
Specifying -march=opteron alone works as intended.

By running gcc -v I see:

% g++ -MD -D_FILE_OFFSET_BITS=64 -O3 -march=native -pipe -fvisibility-inlines-hidden -O3 -pipe -march=opteron -mtune=generic -ggdb3 -std=gnu++11 -Wall -Wextra -Wpedantic -Wno-unused-parameter -c -o metasplit.o metasplit.cc -v 
Using built-in specs.
COLLECT_GCC=g++
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 6-20160117-1' --with-bugurl=file:///usr/share/doc/gcc-6/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-6 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-6-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-6-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-6-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --with-arch-32=i586 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 6.0.0 20160117 (experimental) [trunk revision 232481] (Debian 6-20160117-1) 
COLLECT_GCC_OPTIONS='-MD' '-D' '_FILE_OFFSET_BITS=64' '-O3' '-march=native' '-pipe' '-fvisibility-inlines-hidden' '-O3' '-pipe' '-march=opteron' '-mtune=generic' '-ggdb3' '-std=gnu++11' '-Wall' '-Wextra' '-Wpedantic' '-Wno-unused-parameter' '-c' '-o' 'metasplit.o' '-v' '-shared-libgcc'
 /usr/lib/gcc/x86_64-linux-gnu/6/cc1plus -quiet -v -imultiarch x86_64-linux-gnu -MD metasplit.d -MQ metasplit.o -dD -D_GNU_SOURCE -D _FILE_OFFSET_BITS=64 metasplit.cc -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 -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-clwb -mno-pcommit -mno-mwaitx -mno-clzero -mno-pku -quiet -dumpbase metasplit.cc -march=opteron -mtune=generic -auxbase-strip metasplit.o -ggdb3 -O3 -O3 -Wall -Wextra -Wpedantic -Wno-unused-parameter -std=gnu++11 -version -fvisibility-inlines-hidden -o - |
 as -v --64 -o metasplit.o

It becomes obvious why is that: -march=native gets expanded to all host-specific instructions, while the next -march=opteron doesn't reset them.

Since I generally override the default flags in makefiles by appending
exceptions where needed, I expect the regular behavior where the last flags overrides previous ones and thus found the current behavior unexpected.

I originally discovered this problem in gcc 5.2, but it's still present in all further versions.
Comment 1 Jonathan Wakely 2016-01-25 17:38:16 UTC
Some discussion at https://gcc.gnu.org/ml/gcc/2016-01/msg00000.html

However ...

(In reply to wavexx from comment #0)
> Since I generally override the default flags in makefiles by appending
> exceptions where needed, I expect the regular behavior where the last flags
> overrides previous ones and thus found the current behavior unexpected.

Why would either you or the makefile add something like -march=opteron on a haswell host?

Surely the makefile should only add option that make sense, and you should only override them with options that make sense.
Comment 2 wavexx 2016-01-25 17:51:14 UTC
On 25/01/16 18:38, redi at gcc dot gnu.org wrote:
> Why would either you or the makefile add something like -march=opteron on a
> haswell host?
> 
> Surely the makefile should only add option that make sense, and you should only
> override them with options that make sense.

I generally use -march=native for most of my in-house projects.

However, on very few binaries part of a larger project I actually target
some older ISAs so I simply append -march=[x] as an exception with the
usual CFLAGS += ....

I could also (as I'm currently doing) splice -march out of CFLAGS and/or
override CFLAGS in the required rules, so it's not a huge deal (as
outlined in the original discussion), but even if documented, I would
find the current behavior unexpected.

I would have expected -march=native to simply expand to -march=haswell
so that I could override it normally as I do for almost everything else.
Comment 3 Manuel López-Ibáñez 2016-01-25 18:42:14 UTC
This is a symptom of a more general problem, which is that the general GCC options machinery does not know which options have a single value (-march=) and which options can have multiple values (-I). If it did, then the command-line could be filtered before processing to keep only the last setting. Some of it is done in prune_options but either it happens too late (after the driver has already messed up the command-line) or it only applies to negated options.
Comment 4 wavexx 2016-01-26 12:15:15 UTC
Since I couldn't find documentation for it either, doesn't
-march=haswell by itself imply all associated ISA features?

If so, why -march=native expands to all individual features explicitly?
Comment 5 Thiago Macieira 2018-11-05 18:31:14 UTC
Same thing here. User passes CFLAGS="-march=native" for their system, but library needs to build one .cpp source with -march=haswell for additional functionality (runtime-checked via CPUID). Unfortunately, -march=native supersedes all other -march options, regardless of order, unlike all other options.

Examples:
$ gcc -dM -E -xc /dev/null -march=sandybridge -march=haswell  | grep AVX 
#define __AVX__ 1
#define __AVX2__ 1
$ gcc -dM -E -xc /dev/null -march=haswell -march=sandybridge  | grep AVX
#define __AVX__ 1

$ gcc -dM -E -xc /dev/null -march=sandybridge -march=native | grep AVX
#define __AVX__ 1
#define __AVX2__ 1
$ gcc -dM -E -xc /dev/null -march=native  -march=sandybridge | grep AVX
#define __AVX__ 1
#define __AVX2__ 1

Qt is affected: https://bugreports.qt.io/browse/QTBUG-71564. The problem began when we switched from appending -mavx2 to appending -march=haswell, so we'd get FMA and BMI1/2 in the same file.
Comment 6 Thiago Macieira 2018-11-05 18:36:24 UTC
Clang is not affected:

$ clang -dM -E -xc /dev/null -march=sandybridge -march=native | grep AVX
#define __AVX2__ 1
#define __AVX__ 1
$ clang -dM -E -xc /dev/null -march=native  -march=sandybridge | grep AVX
#define __AVX__ 1

Instead of enabling the CPU features your CPU has, Clang tries to guess which CPU you have and will apply it. This has side-effects for non-arch-specific items like AES.

ICC is similarly affected, despite claiming it isn't:

$ icc -dM -E -xc /dev/null -march=sandybridge  -march=native | grep AVX
icc: command line warning #10121: overriding '-march=sandybridge' with '-march=native'
icc: command line warning #10121: overriding '-march=sandybridge' with '-march=native'
#define __AVX_I__ 1
#define __AVX__ 1
#define __AVX2__ 1
$ icc -dM -E -xc /dev/null -march=native -march=sandybridge | grep AVX               
icc: command line warning #10121: overriding '-march=native' with '-march=sandybridge'
#define __AVX_I__ 1
#define __AVX__ 1
#define __AVX2__ 1

It says it's overriding, but doesn't override.
Comment 7 H.J. Lu 2019-02-08 13:37:47 UTC
-march=native overrides everything, including, -march= after it:

[hjl@gnu-cfl-2 gcc]$ cat /tmp/foo.c
#ifndef __AVX512F__
# error No AVX512F
#endif
[hjl@gnu-cfl-2 gcc]$ ./xgcc -B./ -march=skylake-avx512  -S /tmp/foo.c
[hjl@gnu-cfl-2 gcc]$ ./xgcc -B./ -march=native -march=skylake-avx512  -S /tmp/foo.c
/tmp/foo.c:2:3: error: #error No AVX512F
    2 | # error No AVX512F
      |   ^~~~~
[hjl@gnu-cfl-2 gcc]$
Comment 8 H.J. Lu 2019-02-08 23:02:55 UTC
A patch is posted at

https://gcc.gnu.org/ml/gcc-patches/2019-02/msg00490.html
Comment 9 H.J. Lu 2019-02-19 13:52:08 UTC
A patch is posted at

https://gcc.gnu.org/ml/gcc-patches/2019-02/msg01071.html
Comment 10 hjl@gcc.gnu.org 2019-02-23 19:40:07 UTC
Author: hjl
Date: Sat Feb 23 19:39:35 2019
New Revision: 269164

URL: https://gcc.gnu.org/viewcvs?rev=269164&root=gcc&view=rev
Log:
driver: Also prune joined switches with negation

When -march=native is passed to host_detect_local_cpu to the backend,
it overrides all command lines after it.  That means

$ gcc -march=native -march=skylake-avx512

is the treated as

$ gcc -march=skylake-avx512 -march=native

Prune joined switches with Negative and RejectNegative to allow
-march=skylake-avx512 to override previous -march=native on command-line.

gcc/

	PR driver/69471
	* opts-common.c (prune_options): Also prune joined switches
	with Negative and RejectNegative.
	* config/i386/i386.opt (march=): Add Negative(march=).
	(mtune=): Add Negative(mtune=).
	* doc/options.texi: Document Negative used together with Joined
	and RejectNegative.

gcc/testsuite/

	PR driver/69471
	* gcc.dg/pr69471-1.c: New test.
	* gcc.dg/pr69471-2.c: Likewise.
	* gcc.target/i386/pr69471-3.c: Likewise.

Added:
    trunk/gcc/testsuite/gcc.dg/pr69471-1.c
    trunk/gcc/testsuite/gcc.dg/pr69471-2.c
    trunk/gcc/testsuite/gcc.target/i386/pr69471-3.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/i386/i386.opt
    trunk/gcc/doc/options.texi
    trunk/gcc/opts-common.c
    trunk/gcc/testsuite/ChangeLog
Comment 11 Jakub Jelinek 2019-05-03 09:16:20 UTC
GCC 9.1 has been released.
Comment 12 Jakub Jelinek 2019-08-12 08:55:26 UTC
GCC 9.2 has been released.
Comment 13 ktkachov 2019-09-26 10:53:13 UTC
Author: ktkachov
Date: Thu Sep 26 10:52:42 2019
New Revision: 276148

URL: https://gcc.gnu.org/viewcvs?rev=276148&root=gcc&view=rev
Log:
driver: Also prune joined switches with negation

When -march=native is passed to host_detect_local_cpu to the backend,
it overrides all command lines after it.  That means

$ gcc -march=native -march=armv8-a

is treated as

$ gcc -march=armv8-a -march=native

Prune joined switches with Negative and RejectNegative to allow
-march=armv8-a to override previous -march=native on command-line.

This is the same fix as was applied for i386 in SVN revision 269164 but for
aarch64 and arm.

2019-09-26  Matt Turner  <mattst88@gmail.com>

	PR driver/69471
	* config/aarch64/aarch64.opt (march=): Add Negative(march=).
	(mtune=): Add Negative(mtune=).
	(mcpu=): Add Negative(mcpu=).
	* config/arm/arm.opt: Likewise.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/aarch64/aarch64.opt
    trunk/gcc/config/arm/arm.opt
Comment 14 ktkachov 2019-10-01 10:29:12 UTC
Author: ktkachov
Date: Tue Oct  1 10:28:40 2019
New Revision: 276397

URL: https://gcc.gnu.org/viewcvs?rev=276397&root=gcc&view=rev
Log:
driver: Also prune joined switches with negation

2019-10-01  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

	Backport from mainline
	2019-09-26  Matt Turner  <mattst88@gmail.com>

	PR driver/69471
	* config/aarch64/aarch64.opt (march=): Add Negative(march=).
	(mtune=): Add Negative(mtune=).
	(mcpu=): Add Negative(mcpu=).
	* config/arm/arm.opt: Likewise.

Modified:
    branches/gcc-9-branch/gcc/ChangeLog
    branches/gcc-9-branch/gcc/config/aarch64/aarch64.opt
    branches/gcc-9-branch/gcc/config/arm/arm.opt
Comment 15 Jakub Jelinek 2020-03-12 11:59:03 UTC
GCC 9.3.0 has been released, adjusting target milestone.
Comment 16 Richard Biener 2021-06-01 08:07:25 UTC
GCC 9.4 is being released, retargeting bugs to GCC 9.5.
Comment 17 wavexx 2021-06-01 08:26:14 UTC
I wish this would be given a nudge, considering the patch. This has been pushed to new releases since 2016 :(

It's not a show-stopper, but it does cause unexpected behavior which is quite hard to track down and to fix as well in build systems unless you're accounting for it from the start.
Comment 18 Manuel López-Ibáñez 2021-06-01 11:55:00 UTC
(In reply to wavexx from comment #17)
> I wish this would be given a nudge, considering the patch. This has been
> pushed to new releases since 2016 :(

I see several patches have been committed already. Is there any patch pending?
What are the remaining issues?
Comment 19 wavexx 2021-06-01 13:03:56 UTC
I don't follow gcc development too closely. I expected this bug to be closed when the relevant patch was applied automatically, but I could test if this still apllied.

Which gcc release is sufficient to test with all the patches applied?
Is gcc 10.2.1 enough?
Comment 20 H.J. Lu 2021-06-06 13:15:18 UTC
Fixed in GCC 9.3 and above.  GCC 8 branch is closed.
Comment 21 H.J. Lu 2021-12-20 00:46:13 UTC
*** Bug 42444 has been marked as a duplicate of this bug. ***