GCC 13.2 does not generate sign-extension for value to be compared with the result of `lr.w` instruction in `__atomic_compare_exchange`: https://godbolt.org/z/nafKhPa1Y Code: ``` void foo(uint32_t *p) { uintptr_t x = *(uintptr_t *)p; uint32_t e = !p ? 0 : (uintptr_t)p >> 1; uint32_t d = (uintptr_t)x; __atomic_compare_exchange(p, &e, &d, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); } ``` Assembly generated by `gcc -O3`: ``` foo: ld a4,0(a0) srli a5,a0,1 1: lr.w a3,0(a0); bne a3,a5,1f; sc.w a2,a4,0(a0); bnez a2,1b; 1: ret ``` Which `a5` should be sign-extended, since the RISC-V ISA manual says `lr.w` returns a sign-extended value in RV64. But `gcc -O3 -fno-delete-null-pointer-checks` generates correct code: ``` foo: ld a4,0(a0) li a5,0 beq a0,zero,.L2 srli a5,a0,1 sext.w a5,a5 .L2: 1: lr.w a3,0(a0); bne a3,a5,1f; sc.w a2,a4,0(a0); bnez a2,1b; 1: ret ``` `gcc -O3 -fno-tree-ter`'s output is slight different, but also sign-extended. `clang -O3` always generates correct code: ``` foo: # @foo lw a1, 0(a0) srli a2, a0, 1 sext.w a2, a2 .LBB0_1: # =>This Inner Loop Header: Depth=1 lr.w a3, (a0) bne a3, a2, .LBB0_3 sc.w a4, a1, (a0) bnez a4, .LBB0_1 .LBB0_3: ret ```
foo(unsigned int*): srli a5,a0,1 ld a4,0(a0) 1: lr.w a3,0(a0) bne a3,a5,1f sc.w a2,a4,0(a0) bnez a2,1b 1: ret foo: ld a4,0(a0) srli a5,a0,1 1: lr.w a3,0(a0); bne a3,a5,1f; sc.w a2,a4,0(a0); bnez a2,1b; 1: ret
The master branch has been updated by Kito Cheng <kito@gcc.gnu.org>: https://gcc.gnu.org/g:fd07a29e39f5347d6cef3e7042a32306f97a1719 commit r14-9231-gfd07a29e39f5347d6cef3e7042a32306f97a1719 Author: Kito Cheng <kito.cheng@sifive.com> Date: Wed Feb 28 16:01:52 2024 +0800 RISC-V: Fix __atomic_compare_exchange with 32 bit value on RV64 atomic_compare_and_swapsi will use lr.w to do obtain the original value, which sign extends to DI. RV64 only has DI comparisons, so we also need to sign extend the expected value to DI as otherwise the comparison will fail when the expected value has the 32nd bit set. gcc/ChangeLog: PR target/114130 * config/riscv/sync.md (atomic_compare_and_swap<mode>): Sign extend the expected value if needed. gcc/testsuite/ChangeLog: * gcc.target/riscv/pr114130.c: New. Reviewed-by: Palmer Dabbelt <palmer@rivosinc.com>
The releases/gcc-13 branch has been updated by Kito Cheng <kito@gcc.gnu.org>: https://gcc.gnu.org/g:fb6ec6df54317ed3f6e6f878b6ea29dbef6bfe2d commit r13-8598-gfb6ec6df54317ed3f6e6f878b6ea29dbef6bfe2d Author: Kito Cheng <kito.cheng@sifive.com> Date: Wed Feb 28 16:01:52 2024 +0800 RISC-V: Fix __atomic_compare_exchange with 32 bit value on RV64 atomic_compare_and_swapsi will use lr.w to do obtain the original value, which sign extends to DI. RV64 only has DI comparisons, so we also need to sign extend the expected value to DI as otherwise the comparison will fail when the expected value has the 32nd bit set. gcc/ChangeLog: PR target/114130 * config/riscv/sync.md (atomic_compare_and_swap<mode>): Sign extend the expected value if needed. gcc/testsuite/ChangeLog: * gcc.target/riscv/pr114130.c: New. Reviewed-by: Palmer Dabbelt <palmer@rivosinc.com> (cherry picked from commit fd07a29e39f5347d6cef3e7042a32306f97a1719)
The releases/gcc-12 branch has been updated by Kito Cheng <kito@gcc.gnu.org>: https://gcc.gnu.org/g:d37be5c0413783c5459c5664b6ffb9f47acfca4e commit r12-10319-gd37be5c0413783c5459c5664b6ffb9f47acfca4e Author: Kito Cheng <kito.cheng@sifive.com> Date: Wed Feb 28 16:01:52 2024 +0800 RISC-V: Fix __atomic_compare_exchange with 32 bit value on RV64 atomic_compare_and_swapsi will use lr.w to do obtain the original value, which sign extends to DI. RV64 only has DI comparisons, so we also need to sign extend the expected value to DI as otherwise the comparison will fail when the expected value has the 32nd bit set. gcc/ChangeLog: PR target/114130 * config/riscv/sync.md (atomic_compare_and_swap<mode>): Sign extend the expected value if needed. gcc/testsuite/ChangeLog: * gcc.target/riscv/pr114130.c: New. Reviewed-by: Palmer Dabbelt <palmer@rivosinc.com> (cherry picked from commit fd07a29e39f5347d6cef3e7042a32306f97a1719)
The releases/gcc-11 branch has been updated by Kito Cheng <kito@gcc.gnu.org>: https://gcc.gnu.org/g:cb68221c59e8f98e107bb5842d319bee3a66b8dc commit r11-11317-gcb68221c59e8f98e107bb5842d319bee3a66b8dc Author: Kito Cheng <kito.cheng@sifive.com> Date: Wed Feb 28 16:01:52 2024 +0800 RISC-V: Fix __atomic_compare_exchange with 32 bit value on RV64 atomic_compare_and_swapsi will use lr.w to do obtain the original value, which sign extends to DI. RV64 only has DI comparisons, so we also need to sign extend the expected value to DI as otherwise the comparison will fail when the expected value has the 32nd bit set. gcc/ChangeLog: PR target/114130 * config/riscv/sync.md (atomic_compare_and_swap<mode>): Sign extend the expected value if needed. gcc/testsuite/ChangeLog: * gcc.target/riscv/pr114130.c: New. Reviewed-by: Palmer Dabbelt <palmer@rivosinc.com> (cherry picked from commit fd07a29e39f5347d6cef3e7042a32306f97a1719)
Fixed on trunk also backport to 11~13 branch.