https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106587
Bug ID: 106587 Summary: RISCV invalid jump address when compiled with -fcall-saved-reg and TCO Product: gcc Version: 11.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: michael.hale48 at gmail dot com Target Milestone: --- Description of bug: When compiling with -fcall-saved on temporary registers, program will perform a jump to a register after it has been restored from the stack. GCC version: gcc version 11.1.0 (GCC) System type: 5.4.0-81-generic #91~18.04.1-Ubuntu SMP x86_64 GCC configuration: ``` /home/mhale/github/riscv-gnu-toolchain/riscv-gcc/configure --target=riscv32-unknown-elf --prefix=/opt/riscv --disable-shared --disable-threads --enable-languages=c,c++ --with-system-zlib --enable-tls --with-newlib --with-sysroot=/opt/riscv/riscv32-unknown-elf --with-native-system-header-dir=/include --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libgomp --disable-nls --disable-tm-clone-registry --src=.././riscv-gcc --disable-multilib --with-abi=ilp32d --with-arch=rv32imfdc --with-tune=rocket 'CFLAGS_FOR_TARGET=-Os -mcmodel=medlow' 'CXXFLAGS_FOR_TARGET=-Os -mcmodel=medlow' ``` GCC command: ``` riscv32-unknown-elf-gcc -nostartfiles -Wall -Wextra -fcall-saved-t{1..6} clobber.c -save-temps -v -o clobber ``` Compiler output: ``` Using built-in specs. COLLECT_GCC=/opt/riscv/bin/riscv32-unknown-elf-gcc COLLECT_LTO_WRAPPER=/opt/riscv/libexec/gcc/riscv32-unknown-elf/11.1.0/lto-wrapper Target: riscv32-unknown-elf Configured with: /home/mhale/github/riscv-gnu-toolchain/riscv-gcc/configure --target=riscv32-unknown-elf --prefix=/opt/riscv --disable-shared --disable-threads --enable-languages=c,c++ --with-system-zlib --enable-tls --with-newlib --with-sysroot=/opt/riscv/riscv32-unknown-elf --with-native-system-header-dir=/include --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libgomp --disable-nls --disable-tm-clone-registry --src=.././riscv-gcc --disable-multilib --with-abi=ilp32d --with-arch=rv32imfdc --with-tune=rocket 'CFLAGS_FOR_TARGET=-Os -mcmodel=medlow' 'CXXFLAGS_FOR_TARGET=-Os -mcmodel=medlow' Thread model: single Supported LTO compression algorithms: zlib gcc version 11.1.0 (GCC) COLLECT_GCC_OPTIONS='-nostartfiles' '-Wall' '-Wextra' '-fcall-saved-t1' '-fcall-saved-t2' '-fcall-saved-t3' '-fcall-saved-t4' '-fcall-saved-t5' '-fcall-saved-t6' '-save-temps' '-v' '-o' 'clobber' '-mtune=rocket' '-march=rv32imfdc' '-mabi=ilp32d' '-march=rv32imfdc' /opt/riscv/libexec/gcc/riscv32-unknown-elf/11.1.0/cc1 -E -quiet -v clobber.c -mtune=rocket -march=rv32imfdc -mabi=ilp32d -march=rv32imfdc -Wall -Wextra -fcall-saved-t1 -fcall-saved-t2 -fcall-saved-t3 -fcall-saved-t4 -fcall-saved-t5 -fcall-saved-t6 -fpch-preprocess -o clobber.i ignoring nonexistent directory "/opt/riscv/riscv32-unknown-elf/usr/local/include" ignoring duplicate directory "/opt/riscv/riscv32-unknown-elf/include" #include "..." search starts here: #include <...> search starts here: /opt/riscv/lib/gcc/riscv32-unknown-elf/11.1.0/include /opt/riscv/lib/gcc/riscv32-unknown-elf/11.1.0/include-fixed /opt/riscv/lib/gcc/riscv32-unknown-elf/11.1.0/../../../../riscv32-unknown-elf/include End of search list. COLLECT_GCC_OPTIONS='-nostartfiles' '-Wall' '-Wextra' '-fcall-saved-t1' '-fcall-saved-t2' '-fcall-saved-t3' '-fcall-saved-t4' '-fcall-saved-t5' '-fcall-saved-t6' '-save-temps' '-v' '-o' 'clobber' '-mtune=rocket' '-march=rv32imfdc' '-mabi=ilp32d' '-march=rv32imfdc' /opt/riscv/libexec/gcc/riscv32-unknown-elf/11.1.0/cc1 -fpreprocessed clobber.i -quiet -dumpbase clobber.c -dumpbase-ext .c -mtune=rocket -march=rv32imfdc -mabi=ilp32d -march=rv32imfdc -Wall -Wextra -version -fcall-saved-t1 -fcall-saved-t2 -fcall-saved-t3 -fcall-saved-t4 -fcall-saved-t5 -fcall-saved-t6 -o clobber.s GNU C17 (GCC) version 11.1.0 (riscv32-unknown-elf) compiled by GNU C version 7.5.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version none GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 GNU C17 (GCC) version 11.1.0 (riscv32-unknown-elf) compiled by GNU C version 7.5.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version none GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: aecc75e33d037bca1725d62ef4fb2c89 COLLECT_GCC_OPTIONS='-nostartfiles' '-Wall' '-Wextra' '-fcall-saved-t1' '-fcall-saved-t2' '-fcall-saved-t3' '-fcall-saved-t4' '-fcall-saved-t5' '-fcall-saved-t6' '-save-temps' '-v' '-o' 'clobber' '-mtune=rocket' '-march=rv32imfdc' '-mabi=ilp32d' '-march=rv32imfdc' /opt/riscv/lib/gcc/riscv32-unknown-elf/11.1.0/../../../../riscv32-unknown-elf/bin/as -v --traditional-format -march=rv32imfdc -march=rv32imfdc -mabi=ilp32d -o clobber.o clobber.s GNU assembler version 2.37 (riscv32-unknown-elf) using BFD version (GNU Binutils) 2.37 COMPILER_PATH=/opt/riscv/libexec/gcc/riscv32-unknown-elf/11.1.0/:/opt/riscv/libexec/gcc/riscv32-unknown-elf/11.1.0/:/opt/riscv/libexec/gcc/riscv32-unknown-elf/:/opt/riscv/lib/gcc/riscv32-unknown-elf/11.1.0/:/opt/riscv/lib/gcc/riscv32-unknown-elf/:/opt/riscv/lib/gcc/riscv32-unknown-elf/11.1.0/../../../../riscv32-unknown-elf/bin/ LIBRARY_PATH=/opt/riscv/lib/gcc/riscv32-unknown-elf/11.1.0/:/opt/riscv/lib/gcc/riscv32-unknown-elf/11.1.0/../../../../riscv32-unknown-elf/lib/:/opt/riscv/riscv32-unknown-elf/lib/ COLLECT_GCC_OPTIONS='-nostartfiles' '-Wall' '-Wextra' '-fcall-saved-t1' '-fcall-saved-t2' '-fcall-saved-t3' '-fcall-saved-t4' '-fcall-saved-t5' '-fcall-saved-t6' '-save-temps' '-v' '-o' 'clobber' '-mtune=rocket' '-march=rv32imfdc' '-mabi=ilp32d' '-march=rv32imfdc' '-dumpdir' 'clobber.' /opt/riscv/libexec/gcc/riscv32-unknown-elf/11.1.0/collect2 -plugin /opt/riscv/libexec/gcc/riscv32-unknown-elf/11.1.0/liblto_plugin.so -plugin-opt=/opt/riscv/libexec/gcc/riscv32-unknown-elf/11.1.0/lto-wrapper -plugin-opt=-fresolution=clobber.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgloss -plugin-opt=-pass-through=-lgcc --sysroot=/opt/riscv/riscv32-unknown-elf -melf32lriscv -o clobber -L/opt/riscv/lib/gcc/riscv32-unknown-elf/11.1.0 -L/opt/riscv/lib/gcc/riscv32-unknown-elf/11.1.0/../../../../riscv32-unknown-elf/lib -L/opt/riscv/riscv32-unknown-elf/lib clobber.o -lgcc --start-group -lc -lgloss --end-group -lgcc COLLECT_GCC_OPTIONS='-nostartfiles' '-Wall' '-Wextra' '-fcall-saved-t1' '-fcall-saved-t2' '-fcall-saved-t3' '-fcall-saved-t4' '-fcall-saved-t5' '-fcall-saved-t6' '-save-temps' '-v' '-o' 'clobber' '-mtune=rocket' '-march=rv32imfdc' '-mabi=ilp32d' '-march=rv32imfdc' '-dumpdir' 'clobber.' ``` Preprocessed file (clobber.i): ``` # 0 "clobber.c" # 0 "<built-in>" # 0 "<command-line>" # 1 "clobber.c" typedef void (*void_fptr)(void); void_fptr fptr = 0; int g0, g1, g2, g3, g4, g5, g6, g7; void a() {} void __attribute__((optimize("O3"))) b(int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7) { g0 = arg0; g1 = arg1; g2 = arg2; g3 = arg3; g4 = arg4; g5 = arg5; g6 = arg6; g7 = arg7; if (fptr) { fptr(); } } int _start() { fptr = a; b(0, 1, 2, 3, 4, 5, 6, 7); return 0; } ``` Additional information: The relevant part of generated assembly is pasted below with annotations: ``` b: lui t0,%hi(g0) sw a0,%lo(g0)(t0) lui a0,%hi(g1) sw a1,%lo(g1)(a0) lui a1,%hi(g2) sw a2,%lo(g2)(a1) lui a2,%hi(g3) addi sp,sp,-16 sw a3,%lo(g3)(a2) lui a3,%hi(g4) sw t1,12(sp) sw a4,%lo(g4)(a3) lui t1,%hi(fptr) lui a4,%hi(g5) sw a5,%lo(g5)(a4) lw t1,%lo(fptr)(t1) lui a5,%hi(g6) sw a6,%lo(g6)(a5) lui a5,%hi(g7) sw a7,%lo(g7)(a5) beq t1,zero,.L2 lw t1,12(sp) <-- t1 restored from stack addi sp,sp,16 jr t1 <-- jump to t1 (fptr) .L2: lw t1,12(sp) addi sp,sp,16 jr ra ``` Since no argument/return value/stack pointer/return address registers were specified with -fcall-saved-reg, it would appear that this usage complies with GCC guidance when using this option. However, t1 is used as the target for the jump even though there are other caller-saved registers available.