riscv-collab / riscv-gnu-toolchain

GNU toolchain for RISC-V, including GCC
Other
3.56k stars 1.17k forks source link

Q Extension No Longer Supported in GCC 14 #1586

Closed jordancarlin closed 1 month ago

jordancarlin commented 1 month ago

The update from GCC 13 to GCC 14 seems to have broken the Q extension. Prior to #1531 including q in the march string worked correctly and compiled quad-precision floating-point instructions. Now it fails before it even begins compiling while checking march. If q is left out of the march string it (unsurprisingly) fails on unrecognized instructions when it hits a q instruction in an assembly file. The exact error message is below.

riscv64-unknown-elf-gcc: error: '-march=rv64gqc': extension 'q' is unsupported standard single letter extension
TommyMurphyTM1234 commented 1 month ago

What does riscv64-unknown-elf-gcc -march=help show?

This is what I get:

/riscv64-unknown-elf-gcc --version
riscv64-unknown-elf-gcc (g04696df0963) 14.2.0
Copyright (C) 2024 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.

/riscv64-unknown-elf-gcc -march=help
All available -march extensions for RISC-V:
        Name                Version
        i                       2.0, 2.1
        e                       2.0
        m                       2.0
        a                       2.0, 2.1
        f                       2.0, 2.2
        d                       2.0, 2.2
        c                       2.0
        v                       1.0
        h                       1.0
        zic64b                  1.0
        zicbom                  1.0
        zicbop                  1.0
        zicboz                  1.0
        ziccamoa                1.0
        ziccif                  1.0
        zicclsm                 1.0
        ziccrse                 1.0
        zicntr                  2.0
        zicond                  1.0
        zicsr                   2.0
        zifencei                2.0
        zihintntl               1.0
        zihintpause             2.0
        zihpm                   2.0
        zmmul                   1.0
        za128rs                 1.0
        za64rs                  1.0
        zawrs                   1.0
        zfa                     1.0
        zfh                     1.0
        zfhmin                  1.0
        zfinx                   1.0
        zdinx                   1.0
        zca                     1.0
        zcb                     1.0
        zcd                     1.0
        zce                     1.0
        zcf                     1.0
        zcmp                    1.0
        zcmt                    1.0
        zba                     1.0
        zbb                     1.0
        zbc                     1.0
        zbkb                    1.0
        zbkc                    1.0
        zbkx                    1.0
        zbs                     1.0
        zk                      1.0
        zkn                     1.0
        zknd                    1.0
        zkne                    1.0
        zknh                    1.0
        zkr                     1.0
        zks                     1.0
        zksed                   1.0
        zksh                    1.0
        zkt                     1.0
        ztso                    1.0
        zvbb                    1.0
        zvbc                    1.0
        zve32f                  1.0
        zve32x                  1.0
        zve64d                  1.0
        zve64f                  1.0
        zve64x                  1.0
        zvfbfmin                1.0
        zvfh                    1.0
        zvfhmin                 1.0
        zvkb                    1.0
        zvkg                    1.0
        zvkn                    1.0
        zvknc                   1.0
        zvkned                  1.0
        zvkng                   1.0
        zvknha                  1.0
        zvknhb                  1.0
        zvks                    1.0
        zvksc                   1.0
        zvksed                  1.0
        zvksg                   1.0
        zvksh                   1.0
        zvkt                    1.0
        zvl1024b                1.0
        zvl128b                 1.0
        zvl16384b               1.0
        zvl2048b                1.0
        zvl256b                 1.0
        zvl32768b               1.0
        zvl32b                  1.0
        zvl4096b                1.0
        zvl512b                 1.0
        zvl64b                  1.0
        zvl65536b               1.0
        zvl8192b                1.0
        zhinx                   1.0
        zhinxmin                1.0
        smaia                   1.0
        smepmp                  1.0
        smstateen               1.0
        ssaia                   1.0
        sscofpmf                1.0
        ssstateen               1.0
        sstc                    1.0
        svinval                 1.0
        svnapot                 1.0
        svpbmt                  1.0
        xcvalu                  1.0
        xcvbi                   1.0
        xcvelw                  1.0
        xcvmac                  1.0
        xcvsimd                 1.0
        xtheadba                1.0
        xtheadbb                1.0
        xtheadbs                1.0
        xtheadcmo               1.0
        xtheadcondmov           1.0
        xtheadfmemidx           1.0
        xtheadfmv               1.0
        xtheadint               1.0
        xtheadmac               1.0
        xtheadmemidx            1.0
        xtheadmempair           1.0
        xtheadsync              1.0
        xtheadvector            1.0
        xventanacondops         1.0

The Q/q extension is not listed there by default so I guess that (since GCC 14?) you may need to explicitly enable such support in the toolchain at configuration and build time?

So far I have been unable to identify a GCC patch on the mailing list that might have caused this change in behaviour between GCC 13 and 14.

TommyMurphyTM1234 commented 1 month ago

Maybe this is relevant...?

But that change dates back 8 years or so...

TommyMurphyTM1234 commented 1 month ago

@cmuellner or @kito-cheng - would you happen to know what patches/changes caused this situation? And why? So far my searches of the patches mailing list for possible candidates/suspects have yielded nothing.

TommyMurphyTM1234 commented 1 month ago

FWIW neither is the Q/q extension listed as an option for -march=... in the GCC documentation:

Nor is any Q/q based ABI listed there either.

I wonder if this gives a clue?

Maybe when Q/q was accepted it was just at the front and but nothing useful happened at the back end and consequently support was removed? Perhaps until hardware implementing Q is available and work is done on GCC to properly support it?

@jordancarlin - with GCC 13 did the compiler ever generate any Q/q instructions for you when that extension was included in the architecture specified?

cmuellner commented 1 month ago

The update from GCC 13 to GCC 14 seems to have broken the Q extension. Prior to #1531 including q in the march string worked correctly and compiled quad-precision floating-point instructions. Now it fails before it even begins compiling while checking march. If q is left out of the march string it (unsurprisingly) fails on unrecognized instructions when it hits a q instruction in an assembly file. The exact error message is below.

Looking into the history of gcc/config/riscv/riscv.cc in GCC, I can't see that there was ever Q support in the GCC's RISC-V backend (e.g. look into the FP moves in riscv_output_move()).

That said, GCC releases before GCC 14 indeed accepted q as part of the march string. This was likely addressed (I would even say fixed) by cleanup in the corresponding parser code (gcc/common/config/riscv/riscv-common.cc) in January 2024. Now only those extensions are accepted, that are indeed supported (i.e., if they are listed in riscv_ext_version_table).

Note, that Binutils has "Q" support (there is an entry for "q" in bfd/elfxx-riscv.c). This explains why it looked like the GNU toolchain had "Q" support.

jordancarlin commented 1 month ago

@TommyMurphyTM1234 @cmuellner Thanks for helping look into this. I know that Q was never listed in the march help documentation. When using Q with gcc 13 it was with assembly files, so GCC wasn’t generating any Q instructions from C, but it was able to compile them into an elf file. If this small amount of support was removed since there was no corresponding backend, what is the best path forward for assembly files that contain Q instructions? https://github.com/openhwgroup/cvw implements Q support, so our tool flow for compiling tests breaks with GCC 14 at the moment.

cmuellner commented 1 month ago

Would it work for you to use the assembler instead of the compiler (e.g. riscv64-unknown-linux-gnu-as -o test.o test.s)?

jordancarlin commented 1 month ago

I'm not as familiar with using the assembler directly so will need to look into it and get back to you. Thanks for the idea.

TommyMurphyTM1234 commented 1 month ago

I'm not as familiar with using the assembler directly so will need to look into it and get back to you. Thanks for the idea.

You just invoke the assembler directly, as @cmuellner suggested by calling riscv64-unknown-elf-as directly rather than via the GCC front end riscv64-unknown-elf-gcc. The latter is normally the recommended way but there can be situations (such as this) where you might need to manually invoke specific tools directly.

The documentation for the assembler is here:

(Thanks for the clarifying info @cmuellner! 👍).

jordancarlin commented 1 month ago

Yes. Just switching to riscv64-unknown-elf-as instead of riscv64-unknown-elf-gcc seems to have dramatically changed what is being output, so investigating why that is.

jordancarlin commented 1 month ago

I suspect it has to do with a file that is #included and the assembler not supporting linking. It looks like I will need to directly call the linker first before using the assembler.

TommyMurphyTM1234 commented 1 month ago

I suspect it has to do with a file that is #included and the assembler not supporting linking. It looks like I will need to directly call the linker first before using the assembler.

That doesn't make sense. Linking is the last step in compiling a program and comes before compilation and assembling. Why would you be calling the linker before the assembler and why would that help at all?

TommyMurphyTM1234 commented 1 month ago

Maybe provide a small self-contained test case and people will be able to advise.

TommyMurphyTM1234 commented 1 month ago

Just for completeness on the original issue, this fails:

git clone https://github.com/riscv-collab/riscv-gnu-toolchain
cd riscv-gnu-toolchain
./configure --prefix=`pwd`/installed-tools --with-arch=rv64gcq
make 2>&1 | tee build.log

...

cp doc/gcc.1 doc/g++.1
/home/user/issue-1586/build-gcc-newlib-stage1/./gcc/xgcc -B/home/user/issue-1586/build-gcc-newlib-stage1/./gcc/  -xc -nostdinc /dev/null -S -o /dev/null -fself-test=../.././gcc/gcc/testsuite/selftests
xgcc: error: '-march=rv64imafdqc_zicsr_zifencei': extension 'q' is unsupported standard single letter extension
xgcc: error: '-march=rv64imafdqc_zicsr_zifencei': extension 'q' is unsupported standard single letter extension
make[2]: *** [../.././gcc/gcc/c/Make-lang.in:153: s-selftest-c] Error 1
rm gfdl.pod gcc.pod gcov-dump.pod gcov-tool.pod fsf-funding.pod gpl.pod cpp.pod gcov.pod lto-dump.pod
make[2]: Leaving directory '/home/user/issue-1586/build-gcc-newlib-stage1/gcc'
make[1]: *** [Makefile:4689: all-gcc] Error 2
make[1]: Leaving directory '/home/user/issue-1586/build-gcc-newlib-stage1'
make: *** [Makefile:651: stamps/build-gcc-newlib-stage1] Error 2
jordancarlin commented 1 month ago

@TommyMurphyTM1234 With GCC 13 we were using the following command in a Makefile to compile tests. I've included one of the simple tests along with the linker script below. The included test doesn't actually have a Q instruction in it because that is a much more complicated test, but should be able to compile with the same options.

%.elf: $(SRCDIR)/%.$(SEXT) WALLY-init-lib.h Makefile
    riscv64-unknown-elf-gcc -g -o $@ -march=rv64gqc_zfa_zba_zbb_zbc_zbs_zfh_zicboz_zicbop_zicbom_zbkb_zbkx_zknd_zkne_zknh -mabi=lp64 -mcmodel=medany -nostartfiles -Tlink.ld $<

example.zip

I changed the Makefile to use the command below, but get a very different result now. I assume this is because it is not using the linker script. Sorry if that was unclear before.

%.elf: $(SRCDIR)/%.$(SEXT) WALLY-init-lib.h Makefile
    riscv64-unknown-elf-as -g -o $@ -march=rv64gqc_zfa_zba_zbb_zbc_zbs_zfh_zicboz_zicbop_zicbom_zbkb_zbkx_zknd_zkne_zknh -mabi=lp64 $<
jordancarlin commented 1 month ago

I suspect it has to do with a file that is #included and the assembler not supporting linking. It looks like I will need to directly call the linker first before using the assembler.

That doesn't make sense. Linking is the last step in compiling a program and comes before compilation and assembling. Why would you be calling the linker before the assembler and why would that help at all?

Oops. Meant after the assembler

TommyMurphyTM1234 commented 1 month ago

@TommyMurphyTM1234 With GCC 13 we were using the following command in a Makefile to compile tests. I've included one of the simple tests along with the linker script below. The included test doesn't actually have a Q instruction in it because that is a much more complicated test, but should be able to compile with the same options.

%.elf: $(SRCDIR)/%.$(SEXT) WALLY-init-lib.h Makefile
  riscv64-unknown-elf-gcc -g -o $@ -march=rv64gqc_zfa_zba_zbb_zbc_zbs_zfh_zicboz_zicbop_zicbom_zbkb_zbkx_zknd_zkne_zknh -mabi=lp64 -mcmodel=medany -nostartfiles -Tlink.ld $<

example.zip

I changed the Makefile to use the command below, but get a very different result now. I assume this is because it is not using the linker script. Sorry if that was unclear before.

%.elf: $(SRCDIR)/%.$(SEXT) WALLY-init-lib.h Makefile
  riscv64-unknown-elf-as -g -o $@ -march=rv64gqc_zfa_zba_zbb_zbc_zbs_zfh_zicboz_zicbop_zicbom_zbkb_zbkx_zknd_zkne_zknh -mabi=lp64 $<

You should probably try changing it with GCC 13 first to ensure that you get the same results with your original Makefile which just calls gcc and the modified one that calls as and ld separately. Once you have the same results doing that then you know what to do for GCC 14.

Your modified version ONLY seems to call as? You need to manually call as for each assembly language source file that has Q instructions in order to create the corresponding object file. You then need to call ld (or the gcc front end) to link these any any other object files, libraries and startup code etc. into a complete ELF file.

(I'm using as, ld and gcc as shorthands for the RISC-V versions here).

jordancarlin commented 1 month ago

Thanks for all the help. Our Q tests are working now. I ended up having to run just the preprocessor of gcc first to handle the #includes, then the assembler for the files that depend on Q, and finally the linker.