From fd07a29e39f5347d6cef3e7042a32306f97a1719 Mon Sep 17 00:00:00 2001 From: Kito Cheng Date: Wed, 28 Feb 2024 16:01:52 +0800 Subject: [PATCH] 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): Sign extend the expected value if needed. gcc/testsuite/ChangeLog: * gcc.target/riscv/pr114130.c: New. Reviewed-by: Palmer Dabbelt --- gcc/config/riscv/sync.md | 9 +++++++++ gcc/testsuite/gcc.target/riscv/pr114130.c | 12 ++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 gcc/testsuite/gcc.target/riscv/pr114130.c diff --git a/gcc/config/riscv/sync.md b/gcc/config/riscv/sync.md index 54bb0a66518a..6f0b5aae08dc 100644 --- a/gcc/config/riscv/sync.md +++ b/gcc/config/riscv/sync.md @@ -353,6 +353,15 @@ (match_operand:SI 7 "const_int_operand" "")] ;; mod_f "TARGET_ATOMIC" { + if (word_mode != mode && operands[3] != const0_rtx) + { + /* We don't have SI mode compare on RV64, so we need to make sure expected + value is sign-extended. */ + rtx tmp0 = gen_reg_rtx (word_mode); + emit_insn (gen_extend_insn (tmp0, operands[3], word_mode, mode, 0)); + operands[3] = simplify_gen_subreg (mode, tmp0, word_mode, 0); + } + emit_insn (gen_atomic_cas_value_strong (operands[1], operands[2], operands[3], operands[4], operands[6], operands[7])); diff --git a/gcc/testsuite/gcc.target/riscv/pr114130.c b/gcc/testsuite/gcc.target/riscv/pr114130.c new file mode 100644 index 000000000000..647e27dab321 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr114130.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc -mabi=lp64" } */ +#include + +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); +} + +/* { dg-final { scan-assembler-bound {sext.w\t} >= 1 } } */ -- 2.43.5