Fix atomic_*cmpset32 on riscv64 with clang.
The lr.w instruction used to read the value from memory sign-extends the value read from memory. GCC sign-extends the 32-bit comparison value passed in whereas clang currently does not. As a result, if the value being compared has the MSB set, the comparison fails for matching 32-bit values when compiled with clang. Use a cast to explicitly sign-extend the unsigned comparison value. This works with both GCC and clang. There is commentary in the RISC-V spec that suggests that GCC's approach is more correct, but it is not clear if the commentary in the RISC-V spec is binding. Reviewed by: mhorne Obtained from: Axiado MFC after: 2 weeks Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D22084
This commit is contained in:
parent
c92f130498
commit
b96562eb86
@ -182,7 +182,7 @@ atomic_cmpset_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
|
||||
"bnez %1, 0b\n"
|
||||
"1:"
|
||||
: "=&r" (tmp), "=&r" (res), "+A" (*p)
|
||||
: "rJ" (cmpval), "rJ" (newval)
|
||||
: "rJ" ((long)(int32_t)cmpval), "rJ" (newval)
|
||||
: "memory");
|
||||
|
||||
return (!res);
|
||||
@ -207,7 +207,7 @@ atomic_fcmpset_32(volatile uint32_t *p, uint32_t *cmpval, uint32_t newval)
|
||||
"sw %0, %3\n" /* Save old value */
|
||||
"2:"
|
||||
: "=&r" (tmp), "=&r" (res), "+A" (*p), "+A" (*cmpval)
|
||||
: "rJ" (*cmpval), "rJ" (newval)
|
||||
: "rJ" ((long)(int32_t)*cmpval), "rJ" (newval)
|
||||
: "memory");
|
||||
|
||||
return (!res);
|
||||
|
Loading…
Reference in New Issue
Block a user