https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118608
Bug ID: 118608 Summary: [14/15 regression][mips64] Lack of sign extension with -Os after r14-6915 Product: gcc Version: 14.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: rtl-optimization Assignee: unassigned at gcc dot gnu.org Reporter: mateuszmar2 at gmail dot com Target Milestone: --- Hi, mips64-octeon2-linux-gnu-gcc v14.2.0 and newer generates wrong instructions for following code compiled with -Os: #include <stdlib.h> #include <stdio.h> #define COUNT 10 typedef unsigned short u16; typedef unsigned int u32; typedef struct NeedleAddress { u16 nId; u16 mId; } NeedleAddress; u32 __attribute__ ((noinline)) prepareNeedle(const u16 upper, const u16 lower) { u32 needleAddress = 0; NeedleAddress *const addr = (NeedleAddress*)(&needleAddress); addr->mId = upper; addr->nId = lower; return needleAddress; } const u32* __attribute__ ((noinline)) findNeedle(const u32 needle, const u32* begin, const u32* end) { while ( begin != end && needle != *begin ) { ++begin; } return begin; } int main() { u32 needle = prepareNeedle(0xDCBA, 0xABCD); u32 haystack[COUNT] = {}; for (int i = 0; i < COUNT; i++) haystack[i] = needle; const u32* result = findNeedle(needle, haystack, haystack + COUNT); if (result == haystack + COUNT) printf("Wrong!\n"); else printf("Good!\n"); return 0; } We noticed this problem after an upgrade from gcc12.2.0 to gcc14.2.0. It seems that sign extension is not done by gcc14 in contrast to gcc12 which does it. The main difference seems to be in findNeedle() function. Its loop is executed COUNT times in case of gcc14 because needle is never equal to *begin: "needle != *begin" comparison in assembly and dump of registers compiled by gcc12: 0x0000000120000b88 <findNeedle+60>: 12120005 beq s0,s2,0x120000ba0 <findNeedle+84> 0x0000000120000b8c <findNeedle+64>: dfbf0028 ld ra,40(sp) 0x0000000120000b90 <findNeedle+68>: 8e020000 lw v0,0(s0) => 0x0000000120000b94 <findNeedle+72>: 1451000a bne v0,s1,0x120000bc0 <findNeedle+116> 0x0000000120000b98 <findNeedle+76>: df998090 ld t9,-32624(gp) (gdb) info registers zero at v0 v1 R0 0000000000000000 0000000000000001 ffffffffabcddcba 0000000000000001 a0 a1 a2 a3 R4 ffffffffabcddcba 00000001200112a0 00000001200112c8 000000fff7f70000 a4 a5 a6 a7 R8 0000000000000000 0000000000000004 000000fff7fa0b40 0000000000000000 t0 t1 t2 t3 R12 0000000120011290 0000000000000003 0000000000000000 000000fff7fe6fff s0 s1 s2 s3 R16 00000001200112a0 ffffffffabcddcba 00000001200112c8 0000000120000c60 s4 s5 s6 s7 R20 0000000120000910 000000ffffffcc78 000000fff7ffae80 000000fff7ffb7d8 t8 t9 k0 k1 R24 0000000000000000 0000000120000b4c 0000000000000000 0000000000000000 gp sp s8 ra R28 0000000120018ca0 000000ffffffcaa0 0000000120010c88 0000000120000988 status lo hi badvaddr 0000000000009cf3 0000000000000028 0000000000000000 0000000120011008 cause pc 0000000000800024 0000000120000b94 fcsr fir restart 00000000 00f30000 0000000000000000 "needle != *begin" comparison in assembly and dump of registers compiled by gcc14: 0x000000aaaaaa0c58 <findNeedle+60>: 12120005 beq s0,s2,0xaaaaaa0c70 <findNeedle+84> 0x000000aaaaaa0c5c <findNeedle+64>: dfbf0028 ld ra,40(sp) 0x000000aaaaaa0c60 <findNeedle+68>: 8e020000 lw v0,0(s0) => 0x000000aaaaaa0c64 <findNeedle+72>: 1451000a bne v0,s1,0xaaaaaa0c90 <findNeedle+116> 0x000000aaaaaa0c68 <findNeedle+76>: df998098 ld t9,-32616(gp) (gdb) info registers zero at v0 v1 R0 0000000000000000 0000000000000001 ffffffffabcddcba 0000000000000001 a0 a1 a2 a3 R4 00000000abcddcba 000000aaaaab12a0 000000aaaaab12c8 000000fff7f70000 a4 a5 a6 a7 R8 0000000000000000 0000000000000004 000000fff7fa0b40 0000000000000000 t0 t1 t2 t3 R12 000000aaaaab1290 0000000000000003 0000000000000000 000000fff7fe6fff s0 s1 s2 s3 R16 000000aaaaab12a0 00000000abcddcba 000000aaaaab12c8 000000aaaaaa0d30 s4 s5 s6 s7 R20 000000aaaaaa09c0 000000ffffffcc78 000000fff7ffae80 000000fff7ffb7d8 t8 t9 k0 k1 R24 0000000000000000 000000aaaaaa0c1c 0000000000000000 0000000000000000 gp sp s8 ra R28 000000aaaaab8d70 000000ffffffcaa0 000000aaaaab0d58 000000aaaaaa0a38 status lo hi badvaddr 0000000000009cf3 0000000000000028 0000000000000000 000000aaaaab1008 cause pc 0000000000800024 000000aaaaaa0c64 fcsr fir restart 00000000 00f30000 0000000000000000 gcc14 version of findNeedle() functions gets the value of needle in a0 as 0x00000000abcddcba But when the same value is loaded from the memory to the v0 register, the value is sign extended to 0xffffffffabcddcba It's not a problem in case of gcc12 because the value of needle in a0 is already sign extended: ffffffffabcddcba We did a bisect and found a commit, which introduced this problem: r14-6915 The only difference in assembly code between gcc14.2.0 and gcc14.2.0 with r14-6915 reverted is: 0000000000000c10 <prepareNeedle>: - c10: 00052c38 dsll a1,a1,0x10 + c10: 7ca4fc07 dins a0,a1,0x10,0x10 c14: 03e00008 jr ra - c18: 00a41025 or v0,a1,a0 + c18: 7082f83a exts v0,a0,0x0,0x1f Indeed sign extension will be done only in the second case. Our compiler was configured with following options: --target=mips64-octeon2-linux-gnu --disable-silent-rules --disable-dependency-tracking --enable-clocale=generic --with-gnu-ld --enable-shared --enable-languages=c,c++ --enable-threads=posix --enable-multilib --enable-default-pie --enable-c99 --enable-long-long --enable-symvers=gnu --enable-libstdcxx-pch --program-prefix=mips64-octeon2-linux-gnu- --without-local-prefix --disable-install-libiberty --disable-libssp --enable-libitm --enable-lto --disable-bootstrap --with-system-zlib --enable-linker-build-id --with-ppl=no --with-cloog=no --enable-checking=release --enable-cheaders=c_global --without-isl --with-plugin-ld=ld --enable-poison-system-directories --disable-static --disable-nls --with-glibc-version=2.28 --with-abi=64 --disable-plugin --enable-fix-cortex-a53-835769 --enable-__cxa_atexit --enable-libmudflap --enable-libgomp --enable-cxx-flags='-O2 -g -mabi=64 -march=octeon2' --with-arch=octeon2 --without-fp --with-float=soft --disable-fixed-point --with-mips-plt --with-abi=64