https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127867
Bug ID: 127867
Summary: [m68k] -m68020-60 or -m68020-40 with -mcpu=/-march=
(or -m68040, -m68060, ...) passes the assembler a
single bogus option such as "-m68040-mcpu=68040"
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: davidrogers at me dot com
Target Milestone: ---
Created attachment 65821
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65821&action=edit
Patch file for the 68k spec patch.
Discovered while working with Claude for some mac68k NetBSD development. Though
I had seen this bug previously. The remainder of the description and history is
from Claude as well as the patch. From my understanding, it will need a sign
off being that this is AI assisted but it's also under the limit of 15 lines.
I'll leave the decision up to everyone here.
`ASM_CPU_SPEC` in `gcc/config/m68k/m68k.h` is
%{m68851}%{mno-68851} %{m68881}%{mno-68881} %{msoft-float:-mno-float} \
%{m68020-40:-m68040}%{m68020-60:-m68040}\
%{mcpu=*:-mcpu=%*}%{march=*:-march=%*}\
There is no space between `%{m68020-60:-m68040}` and `%{mcpu=*:-mcpu=%*}`,
so when both match, the driver hands `as` one argument made of both. Since
r172130 (2011-04-07, "m68k.c (m68k_handle_option): Don't handle
OPT_m68000..."), `-m68000` ... `-m68060` are aliases of `-mcpu=`, so the
everyday form `-m68020-60 -m68040` hits it too:
$ m68k-netbsdelf-gcc -m68020-60 -m68040 -c t.c
Assembler messages:
Error: unrecognized option `-m68040-mcpu=68040'
`-###` shows `as "-m68040-mcpu=68040"`. The same happens with
`-m68020-60 -mcpu=68040` (`"-m68040-mcpu=68040"`), `-m68020-60 -march=68040`
(`"-m68040-march=68040"`) and `-m68020-40 -m68060` (`"-m68040-mcpu=68060"`).
Each option alone works.
This is how it shows up in practice: NetBSD/mac68k's kernel build always
passes `-m68020-60` (CMACHFLAGS), so adding `-m68040` to tune a 68040-only
kernel fails to assemble every file.
## Why the combination is valid
The manual defines `-m68020-60` as "equivalent to `-march=68020
-mtune=68020-60`" (and `-m68020-40` likewise), and `-m68040` etc. are
aliases of `-mcpu=`. The documented rule, also in the comment in
`m68k_option_override`, is that `-mcpu=` overrides `-march=` and `-mtune=`
applies on top. cc1 accepts every combination above without a warning and
generates the expected code (the options are processed in order, last one
winning, in `m68k_handle_option`); `OPTION_DEFAULT_SPECS` also tests
`-m68020-60` alongside `-mcpu=`. Only the assembler spec mishandles it.
## History
- GCC 4.3.0 (from the 2007-01-12 CodeSourcery -mcpu=/-march= rework) put
`%{mcpu=*:-mcpu=%*}` in ASM_CPU_SPEC; until 4.6 the separate `%{m68040}`,
`%{m68060}`, ... pass-throughs sat between it and `%{m68020-60:-m68040}`.
- r172130 (Joseph Myers, 2011-04-07; git 39e7722bbfdc), first released in
4.7.0, made the old CPU switches aliases of -mcpu= and removed their
pass-throughs, leaving `%{m68020-60:-m68040}` directly against
`%{mcpu=*:-mcpu=%*}`. Unchanged since.
- By inspection, 4.3-4.6 probably glued `-m68020-60 -mcpu=...` the same
way (nothing in between unless another CPU switch was given); not tested.
## Workaround
Don't give GCC both a range option (`-m68020-40`, `-m68020-60`) and a
specific CPU (`-mcpu=`, `-march=`, `-m68000` ... `-m68060`): pick one. To
build for a 68040 alone, use `-m68040` instead of `-m68020-60`, not in
addition to it. Where a build system always adds `-m68020-60`, replace its
setting rather than appending; for NetBSD/mac68k that's
`makeoptions CMACHFLAGS="-m68040 -Wa,-m68030 -Wa,-mcpu=68030 -Wa,-m68851"`
in the kernel config, with `Makefile.mac68k` patched to let a config set
it (see `netbsd-m68k-cmachflags.md`). Without changing the build, a
`-specs=` file overriding `*asm_cpu_spec:` with the fixed spec below also
works (`gcc-m68k-asm-cpu-spec.specs`).
## Suggested fix
Only emit the `-m68040` that stands for -m68020-40/-m68020-60 when no
explicit -mcpu=/-march= is given (adding spaces alone is not enough:
`-m68020-40 -m68060` then hands `as` `-m68040 -mcpu=68060`, which it
rejects with "selected processor does not have all features of selected
architecture"):
#define ASM_CPU_SPEC "\
%{m68851}%{mno-68851} %{m68881}%{mno-68881} %{msoft-float:-mno-float} \
%{!mcpu=*:%{!march=*:%{m68020-40:-m68040}%{m68020-60:-m68040}}} \
%{mcpu=*:-mcpu=%*} %{march=*:-march=%*}\
"
One limitation: specs can't see option order, so with `-m68040 -m68020-60`
(cc1: -mcpu=68020, last wins) this still passes `as -mcpu=68040`. That
assembles (68040 accepts 68020 code), but matching cc1 exactly would need the
driver to resolve the CPU first.
The patch against current master is `gcc-m68k-asm-cpu-spec.patch`.
Tested with a -specs= override on m68k--netbsdelf-gcc 12.5.0
(`gcc-m68k-asm-cpu-spec.specs` here): every combination above assembles,
and -m68020-60, -m68020-40, -m68040, -mcpu=68060, -m68000, -mcpu=5475 and no
option pass `as` the same options as before. Not yet bootstrapped or run
through the testsuite.