NetBSD Problem Report #56839

From www@netbsd.org  Mon May 16 15:13:18 2022
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id CA1881A921F
	for <gnats-bugs@gnats.NetBSD.org>; Mon, 16 May 2022 15:13:18 +0000 (UTC)
Message-Id: <20220516151317.5F00B1A923A@mollari.NetBSD.org>
Date: Mon, 16 May 2022 15:13:17 +0000 (UTC)
From: rokuyama.rk@gmail.com
Reply-To: rokuyama.rk@gmail.com
To: gnats-bugs@NetBSD.org
Subject: GCC emits wrong codes for compare_and_swap_1 bultins on armv5 (el & eb)
X-Send-Pr-Version: www-1.0

>Number:         56839
>Category:       port-arm
>Synopsis:       GCC emits wrong codes for compare_and_swap_1 bultins on armv5 (el & eb)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-arm-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon May 16 15:15:00 +0000 2022
>Last-Modified:  Thu Mar 19 19:50:01 +0000 2026
>Originator:     Rin Okuyama
>Release:        9.99.96
>Organization:
Department of Physics, Meiji University
>Environment:
NetBSD hdlg 9.99.96 NetBSD 9.99.96 (HDL_G) #5: Sun May 15 19:24:35 JST 2022  rin@latipes:/build/src/sys/arch/evbarm/compile/HDL_G evbarm
>Description:
Tests for __sync_{bool,val}_compare_and_swap_1() fail on armv5:

https://www.netbsd.org/~martin/evbarm-atf/402_atf.html#lib_libc_atomic_t___sync_compare_and_swap___sync_bool_compare_and_swap_1

These failures are observed both for little- and big-endian.

This is because GCC emits wrong codes for these built-in functions.
For some cases, GCC uses "mvn" insn to generate 2nd ("expected") and
3rd ("new") arguments for these builtins.

For example, it emits "mvn reg,#0x77" for 0x88, which results in
0xffffff88. This is wrong as these arguments are passed via registers;
inappropriate 0xff's in upper 3 bytes for "expected" argument make
comparison with uint8_t value of "*ptr" unconditionally fail.

This kind of wrong immediate generations are not observed for other
functions that take uint8_t arguments. Therefore, something is wrong
for treatments peculiar to these builtins.

Note that Linux version of __sync_bool_compare_and_swap_N() takes
signed integers as the 2nd and 3rd arguments on arm, whereas these are
unsigned for us. This may be related to this wrong "sign-extension".

The above-mentioned scenario is confirmed by a minimal stripped-down
version of the test for __sync_bool_compare_and_swap_1() (and
_atomic_cas_8(), which is used internally for this builtin):

https://gist.github.com/rokuyama/f469cbf96774db1f4658f0bb932c7a23

It fails for __sync_bool_compare_and_swap_1(), and succeeds for
_atomic_cas_8():

----
$ cc -g -O2 -c arm_builtin_compare_and_swap_1.c
$ cc arm_builtin_compare_and_swap_1.o
$ ./a.out
__sync_bool_compare_and_swap_1: val expects 0xf0 but 0x88
----

(Here, "-O2" is only for readability of objdump (see below).
The same failure occurs even with "-O0".)

objdump for this test case reads:

https://gist.github.com/rokuyama/eaf499d1e57767dbbe3e7bf30b2e0fce

Here, GCC generates 0x88 by "mvn" and "mov" for arguments for
__sync_bool_compare_and_swap_1() and _atomic_cas_8(), respectively.
>How-To-Repeat:
cd /usr/tests/lib/libc/atomic && atf-run t___sync_compare_and_swap

The stripped-down version of this test is provided above.
>Fix:
N/A

>Audit-Trail:
From: Nick Hudson <nick.hudson@gmx.co.uk>
To: gnats-bugs@netbsd.org, port-arm-maintainer@netbsd.org,
 gnats-admin@netbsd.org, netbsd-bugs@netbsd.org
Cc: 
Subject: Re: port-arm/56839: GCC emits wrong codes for compare_and_swap_1
 bultins on armv5 (el & eb)
Date: Wed, 18 May 2022 12:48:54 +0100

 I think this fixes things. It's a bit ugly...

 https://www.netbsd.org/~skrll/pr56839.diff

 Nick

From: Rin Okuyama <rokuyama.rk@gmail.com>
To: Nick Hudson <nick.hudson@gmx.co.uk>, gnats-bugs@netbsd.org,
 port-arm-maintainer@netbsd.org, gnats-admin@netbsd.org,
 netbsd-bugs@netbsd.org
Cc: 
Subject: Re: port-arm/56839: GCC emits wrong codes for compare_and_swap_1
 bultins on armv5 (el & eb)
Date: Fri, 20 May 2022 10:32:32 +0900

 Hi,

 On 2022/05/18 20:48, Nick Hudson wrote:
 > I think this fixes things. It's a bit ugly...
 > 
 > https://www.netbsd.org/~skrll/pr56839.diff

 This does not work:

 (1) GCC expands __sync_bool_compare_and_swap_N() into
      __sync_val_compare_and_swap_N() as optimization.

 (2) The patch does not cover __sync_val_compare_and_swap_N()
      ( == _atomic_cas_8N() ).

 On the other hand, this patch for _atomic_cas_8N() fixes the problem:

 https://gist.github.com/rokuyama/3d791f2ceb2757dc389a95910162c9cb

 However, IMO, this is not the real fix:

 (a) I've found that MI part, not arm-dependent part, of GCC carries
      out sign-extension; something is wrong in
      expand_builtin_compare_and_swap() @ dist/gcc/gcc/builtins.c,
      but I've never fully understand what goes wrong yet...
      (Strangely enough, GCC itself recognizes that these builtins
      takes unsigned integers...)

 (b) Therefore, archs other than arm that do not have 1- and 2-byte
      atomic cas builtins (== missing equivalent instructions) should
      be affected.

 (c) It should be better to fix GCC rather than adding workaround to
      libc routines.

 Thanks,
 rin

From: Rin Okuyama <rokuyama.rk@gmail.com>
To: "gnats-bugs@NetBSD.org" <gnats-bugs@netbsd.org>, netbsd-bugs@netbsd.org
Cc: 
Subject: Re: port-arm/56839 (GCC emits wrong codes for compare_and_swap_1
 bultins on armv5 (el & eb))
Date: Tue, 15 Aug 2023 13:02:24 +0900

 This still fails in the same manner even for GCC 12.3.0 and 10.5.0.

From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: port-arm/56839: GCC emits wrong codes for compare_and_swap_1
 builtins
Date: Wed, 5 Feb 2025 11:50:18 +0100

 I am not convinced GCC is wrong here. The ABI says the caller needs to
 0-extend or sign-extend the sub-word value and pass it as a 32bit register
 value. So it all boils down to what the signature of the called function
 is - and unfortunately that seems to be poorly or not documented anywhere.

 But: gcc/dist/libgcc/config/arm/ implements the functions as taking
 signed values - so that would match the gcc generated call sites.

 #define SUBWORD_VAL_CAS(TYPE, WIDTH)                                    \
   TYPE HIDDEN                                                           \
   __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval,          \
                                        TYPE newval)                     \

 SUBWORD_VAL_CAS (short,       2)
 SUBWORD_VAL_CAS (signed char, 1)


 I think we need to make our functions match that (basically Nick's patch,
 plus maybe extensions to a few other functions).

 Martin

From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/56839 CVS commit: src/tests/lib/libc/atomic
Date: Thu, 13 Mar 2025 14:00:51 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Thu Mar 13 14:00:51 UTC 2025

 Modified Files:
 	src/tests/lib/libc/atomic: t___sync_compare_and_swap.c

 Log Message:
 tests/lib/libc/atomic: Test subword compare-and-swap explicitly.

 Make sure the sign doesn't bleed into an adjacent word.

 We already had failing tests, but this should make the failures a
 little more obvious and perhaps check for more adjacent problems.

 PR port-arm/56839: GCC emits wrong codes for compare_and_swap_1
 bultins on armv5 (el & eb)


 To generate a diff of this commit:
 cvs rdiff -u -r1.1 -r1.2 \
     src/tests/lib/libc/atomic/t___sync_compare_and_swap.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: Taylor R Campbell <riastradh@NetBSD.org>
To: Rin Okuyama <rokuyama.rk@gmail.com>,
	Nick Hudson <nick.hudson@gmx.co.uk>,
	Martin Husemann <martin@duskware.de>
Cc: gnats-bugs@NetBSD.org, netbsd-bugs@NetBSD.org
Subject: Re: port-arm/56839: GCC emits wrong codes for compare_and_swap_1 bultins on armv5 (el & eb)
Date: Thu, 13 Mar 2025 14:29:40 +0000

 It looks like gcc is _inconsistent_ about the signedness of the
 __sync_* builtins.  Here, for example, in gcc-14.2.0, it appears to
 use unsigned arguments in libgcc:

  134 typedef unsigned int UQItype __attribute__((mode (QI)));
  135 DEFINE (FN, 1, UQItype)
 ...
  139 typedef unsigned int UHItype __attribute__((mode (HI)));
  140 DEFINE (FN, 2, UHItype)
 ...
  144 typedef unsigned int USItype __attribute__((mode (SI)));
  145 DEFINE (FN, 4, USItype)
 ...

 https://gcc.gnu.org/git/?p=3Dgcc.git;a=3Dblob;f=3Dlibgcc/sync.c;h=3D6ffe88a=
 ac0f08d1adbc0b02f7f10d50d95d4c6eb;hb=3D04696df09633baf97cdbbdd6e9929b9d4721=
 61d3#l125

 And, for _FreeBSD_ on arm32, it also uses unsigned arguments:

  220 EMIT_ALL_OPS_N (1, unsigned char, "ldrb", "strb", "streqb")
  221 EMIT_ALL_OPS_N (2, unsigned short, "ldrh", "strh", "streqh")
  222 EMIT_ALL_OPS_N (4, unsigned int, "ldr", "str", "streq")

 https://gcc.gnu.org/git/?p=3Dgcc.git;a=3Dblob;f=3Dlibgcc/config/arm/freebsd=
 -atomic.c;h=3D7cf00b1e75d4759b983401797f0224764a2ce82d;hb=3D04696df09633baf=
 97cdbbdd6e9929b9d472161d3#l220

 But elsewhere, e.g. for _Linux_ on arm32, it uses signed arguments:

  249 SUBWORD_VAL_CAS (short,       2)
  250 SUBWORD_VAL_CAS (signed char, 1)

 https://gcc.gnu.org/git/?p=3Dgcc.git;a=3Dblob;f=3Dlibgcc/config/arm/linux-a=
 tomic.c;h=3D6d6683194aff0404967b28030bc7677b0f2e5949;hb=3D04696df09633baf97=
 cdbbdd6e9929b9d472161d3#l249

 And I have no idea about the code generation parts of things.

 We should file a bug upstream, perhaps.

 But until we do, I think it should be sufficient to write all of our
 __sync_* routines -- including both __sync_bool_* and __sync_val_*, of
 course -- with signed arguments and pass them to the unsigned
 _atomic_* functions, like Nick suggested.

 This should paper over the gcc issue, by forcing gcc to generate code
 that always zero-extends the subword when passing arguments in
 registers so the comparison will succeed (at least, for ABIs where
 that is relevant), without requiring changes to our _atomic_*
 definitions which are perfectly good for their signatures.

 I guess it is conceivable that there is an ABI where this will do the
 wrong thing but I doubt it.  Even on riscv64, where 8/16-bit units are
 type-extended to 32 bit and then sign-extended to 64 bits (no matter
 the signedness of the type), I think this will produce the correct
 result.  (Also I think these stubs won't be used on riscv anyway.)=20

From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/56839 CVS commit: src/tests/lib/libc/atomic
Date: Fri, 25 Apr 2025 12:11:14 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Fri Apr 25 12:11:14 UTC 2025

 Modified Files:
 	src/tests/lib/libc/atomic: t___sync_compare_and_swap.c

 Log Message:
 t___sync_compare_and_swap: Mark tests xfail on armv5.

 PR port-arm/56839: GCC emits wrong codes for compare_and_swap_1
 bultins on armv5 (el & eb)


 To generate a diff of this commit:
 cvs rdiff -u -r1.2 -r1.3 \
     src/tests/lib/libc/atomic/t___sync_compare_and_swap.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@netbsd.org
Cc: rokuyama.rk@gmail.com
Subject: Re: PR/56839 CVS commit: src/tests/lib/libc/atomic
Date: Fri, 25 Apr 2025 14:21:38 +0200

 Rin, I would like to resolve this along the lines of the fix suggested
 by skrll (but extended to whatever other primitives that change did
 not cover). Would you be OK with that?

 If so, I'll prepare a patch with the other functions covered.

 Martin

From: Rin Okuyama <rokuyama.rk@gmail.com>
To: Martin Husemann <martin@duskware.de>, gnats-bugs@netbsd.org
Cc: 
Subject: Re: PR/56839 CVS commit: src/tests/lib/libc/atomic
Date: Mon, 28 Apr 2025 14:57:21 +0900

 On 2025/04/25 21:21, Martin Husemann wrote:
 > Rin, I would like to resolve this along the lines of the fix suggested
 > by skrll (but extended to whatever other primitives that change did
 > not cover). Would you be OK with that?
 > 
 > If so, I'll prepare a patch with the other functions covered.

 Thanks, please!!

 // Belatedly, I catched up with this PR. The current GCC behavior is
 // not optimal, but there should be ~ no practical benefits to ``fix''
 // GCC in this case, IMO...

 rin

 > 
 > Martin

From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: PR/56839: GCC emits wrong codes for compare_and_swap_1 bultins
 on armv5 (el & eb)
Date: Thu, 19 Mar 2026 15:27:07 +0100

 I tried what we last discussed (finaly) but new gcc is not happy
 with it:

 ../common/lib/libc/atomic/atomic_init_testset.c:370:1: error: conflicting types for built-in function '__sync_val_compare_and_swap_2'; expected 'short unsigned int(volatile void *, short unsigned int,  short unsigned int)' [-Werror=builtin-declaration-mismatch]
   370 | __sync_val_compare_and_swap_2(volatile int16_t *addr, int16_t old, int16_t new)
       | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~


 Rin, did I misunderstand what you meant to do?
 Or did something get fixed and the __sync_val_compare_and_swap_N optimization
 is now gone?

 Here is the full patch I tested:

 Index: atomic_cas_16_cas.c
 ===================================================================
 RCS file: /cvsroot/src/common/lib/libc/atomic/atomic_cas_16_cas.c,v
 retrieving revision 1.3
 diff -u -p -r1.3 atomic_cas_16_cas.c
 --- atomic_cas_16_cas.c	21 Feb 2014 16:06:48 -0000	1.3
 +++ atomic_cas_16_cas.c	19 Mar 2026 14:25:45 -0000
 @@ -36,12 +36,15 @@
  #endif
  #include <sys/atomic.h>

 -bool bool_compare_and_swap_2(volatile uint16_t *, uint16_t, uint16_t, ...)
 +bool bool_compare_and_swap_2(volatile int16_t *, int16_t, int16_t, ...)
      asm("__sync_bool_compare_and_swap_2");

  bool
 -bool_compare_and_swap_2(volatile uint16_t *addr, uint16_t oldval,
 -	uint16_t newval, ...)
 +bool_compare_and_swap_2(volatile int16_t *addr, int16_t oldval,
 +	int16_t newval, ...)
  {
 -	return atomic_cas_16(addr, oldval, newval) == oldval;
 +	const uint16_t oldv = (uint16_t)oldval;
 +	const uint16_t newv = (uint16_t)newval;
 +
 +	return atomic_cas_16((volatile uint16_t *)addr, oldv, newv) == oldv;
  }
 Index: atomic_cas_32_cas.c
 ===================================================================
 RCS file: /cvsroot/src/common/lib/libc/atomic/atomic_cas_32_cas.c,v
 retrieving revision 1.2
 diff -u -p -r1.2 atomic_cas_32_cas.c
 --- atomic_cas_32_cas.c	8 Jan 2026 08:55:25 -0000	1.2
 +++ atomic_cas_32_cas.c	19 Mar 2026 14:25:45 -0000
 @@ -37,12 +37,15 @@

  #include <sys/atomic.h>

 -bool bool_compare_and_swap_4(volatile uint32_t *, uint32_t, uint32_t, ...)
 +bool bool_compare_and_swap_4(volatile int32_t *, int32_t, int32_t, ...)
      asm("__sync_bool_compare_and_swap_4");

  bool
 -bool_compare_and_swap_4(volatile uint32_t *addr, uint32_t oldval,
 -	uint32_t newval, ...)
 +bool_compare_and_swap_4(volatile int32_t *addr, int32_t oldval,
 +	int32_t newval, ...)
  {
 -	return atomic_cas_32(addr, oldval, newval) == oldval;
 +	const uint32_t oldv = (uint32_t)oldval;
 +	const uint32_t newv = (uint32_t)newval;
 +
 +	return atomic_cas_32((volatile uint32_t *)addr, oldv, newv) == oldv;
  }
 Index: atomic_cas_64_cas.c
 ===================================================================
 RCS file: /cvsroot/src/common/lib/libc/atomic/atomic_cas_64_cas.c,v
 retrieving revision 1.3
 diff -u -p -r1.3 atomic_cas_64_cas.c
 --- atomic_cas_64_cas.c	8 Jan 2026 08:55:25 -0000	1.3
 +++ atomic_cas_64_cas.c	19 Mar 2026 14:25:45 -0000
 @@ -39,14 +39,17 @@

  #ifdef __HAVE_ATOMIC64_OPS

 -bool bool_compare_and_swap_8(volatile uint64_t *, uint64_t, uint64_t, ...)
 +bool bool_compare_and_swap_8(volatile int64_t *, int64_t, int64_t, ...)
      asm("__sync_bool_compare_and_swap_8");

  bool
 -bool_compare_and_swap_8(volatile uint64_t *addr, uint64_t oldval,
 -	uint64_t newval, ...)
 +bool_compare_and_swap_8(volatile int64_t *addr, int64_t oldval,
 +	int64_t newval, ...)
  {
 -	return atomic_cas_64(addr, oldval, newval) == oldval;
 +	const uin64_t oldv = (uint64_t)oldval;
 +	const uin64_t newv = (uint64_t)newval;
 +
 +	return atomic_cas_64((volatile uint64 *)addr, oldv, newv) == oldv;
  }

  #endif
 Index: atomic_cas_8_cas.c
 ===================================================================
 RCS file: /cvsroot/src/common/lib/libc/atomic/atomic_cas_8_cas.c,v
 retrieving revision 1.3
 diff -u -p -r1.3 atomic_cas_8_cas.c
 --- atomic_cas_8_cas.c	21 Feb 2014 16:06:48 -0000	1.3
 +++ atomic_cas_8_cas.c	19 Mar 2026 14:25:45 -0000
 @@ -35,13 +35,17 @@
  #include <stdbool.h>
  #endif
  #include <sys/atomic.h>
 +#include <stdarg.h>

 -bool bool_compare_and_swap_1(volatile uint8_t *, uint8_t, uint8_t, ...)
 +bool bool_compare_and_swap_1(volatile int8_t *, int8_t, int8_t, ...)
      asm("__sync_bool_compare_and_swap_1");

  bool
 -bool_compare_and_swap_1(volatile uint8_t *addr, uint8_t oldval,
 -	uint8_t newval, ...)
 +bool_compare_and_swap_1(volatile int8_t *addr, int8_t oldval,
 +	int8_t newval, ...)
  {
 -	return atomic_cas_8(addr, oldval, newval) == oldval;
 +	uint8_t oldv = (uint8_t)oldval;
 +	uint8_t newv = (uint8_t)newval;
 +
 +	return atomic_cas_8((volatile uint8_t *)addr, oldv, newv) == oldv;
  }
 Index: atomic_cas_by_cas32.c
 ===================================================================
 RCS file: /cvsroot/src/common/lib/libc/atomic/atomic_cas_by_cas32.c,v
 retrieving revision 1.4
 diff -u -p -r1.4 atomic_cas_by_cas32.c
 --- atomic_cas_by_cas32.c	3 Sep 2014 19:30:47 -0000	1.4
 +++ atomic_cas_by_cas32.c	19 Mar 2026 14:25:45 -0000
 @@ -64,7 +64,14 @@ _atomic_cas_16(volatile uint16_t *addr, 
  	return old;
  }

 -crt_alias(__sync_val_compare_and_swap_2,_atomic_cas_16)
 +int16_t
 +__sync_val_compare_and_swap_2(volatile int16_t *addr, int16_t old, int16_t new)
 +{
 +	const uint16_t oldv = (uint16_t)oldval;
 +	const uint16_t newv = (uint16_t)newval;
 +
 +	return _atomic_cas_16((volatile uint16_t *)addr, oldv, newv);
 +}

  uint8_t
  _atomic_cas_8(volatile uint8_t *addr, uint8_t old, uint8_t new)
 @@ -88,4 +95,11 @@ _atomic_cas_8(volatile uint8_t *addr, ui
  	return old;
  }

 -crt_alias(__sync_val_compare_and_swap_1,_atomic_cas_8)
 +int8_t
 +__sync_val_compare_and_swap_1(volatile int8_t *addr, int8_t old, int8_t new)
 +{
 +	const uint8_t oldv = (uint8_t)oldval;
 +	const uint8_t newv = (uint8_t)newval;
 +
 +	return _atomic_cas_8((volatile uint8_t *)addr, oldv, newv);
 +}
 Index: atomic_init_testset.c
 ===================================================================
 RCS file: /cvsroot/src/common/lib/libc/atomic/atomic_init_testset.c,v
 retrieving revision 1.21
 diff -u -p -r1.21 atomic_init_testset.c
 --- atomic_init_testset.c	9 Jan 2026 08:44:57 -0000	1.21
 +++ atomic_init_testset.c	19 Mar 2026 14:25:45 -0000
 @@ -345,8 +345,41 @@ __strong_alias(_atomic_cas_ptr_ni,_atomi
  atomic_op_alias(atomic_cas_64,_atomic_cas_64)
  atomic_op_alias(atomic_cas_64_ni,_atomic_cas_64)
  __strong_alias(_atomic_cas_64_ni,_atomic_cas_64)
 -crt_alias(__sync_val_compare_and_swap_8,_atomic_cas_64)
 +
 +int64_t
 +__sync_val_compare_and_swap_8(volatile int64_t *addr, int64_t old, int64_t new)
 +{
 +	const uint64_t oldv = (uint64_t)old;
 +	const uint64_t newv = (uint64_t)new;
 +
 +	return _atomic_cas_64((volatile uint64_t *)addr, oldv, newv);
 +}
 +
  #endif
 -crt_alias(__sync_val_compare_and_swap_4,_atomic_cas_32)
 -crt_alias(__sync_val_compare_and_swap_2,_atomic_cas_16)
 -crt_alias(__sync_val_compare_and_swap_1,_atomic_cas_8)
 +
 +int32_t
 +__sync_val_compare_and_swap_4(volatile int32_t *addr, int32_t old, int32_t new)
 +{
 +	const uint32_t oldv = (uint32_t)old;
 +	const uint32_t newv = (uint32_t)new;
 +
 +	return _atomic_cas_32((volatile uint32_t *)addr, oldv, newv);
 +}
 +
 +int16_t
 +__sync_val_compare_and_swap_2(volatile int16_t *addr, int16_t old, int16_t new)
 +{
 +	const uint16_t oldv = (uint16_t)old;
 +	const uint16_t newv = (uint16_t)new;
 +
 +	return _atomic_cas_16((volatile uint16_t *)addr, oldv, newv);
 +}
 +
 +int8_t
 +__sync_val_compare_and_swap_1(volatile int8_t *addr, int8_t old, int8_t new)
 +{
 +	const uint8_t oldv = (uint8_t)old;
 +	const uint8_t newv = (uint8_t)new;
 +
 +	return _atomic_cas_8((volatile uint8_t *)addr, oldv, newv);
 +}


 Martin

From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: PR/56839: GCC emits wrong codes for compare_and_swap_1 bultins
 on armv5 (el & eb)
Date: Thu, 19 Mar 2026 20:45:31 +0100

 Here is a patch that seems to work (builds, and makes the xfail tests
 work).

 Did I miss anything else?

 Martin



 Index: atomic_cas_16_cas.c
 ===================================================================
 RCS file: /cvsroot/src/common/lib/libc/atomic/atomic_cas_16_cas.c,v
 retrieving revision 1.3
 diff -u -p -r1.3 atomic_cas_16_cas.c
 --- atomic_cas_16_cas.c	21 Feb 2014 16:06:48 -0000	1.3
 +++ atomic_cas_16_cas.c	19 Mar 2026 19:44:18 -0000
 @@ -36,12 +36,15 @@
  #endif
  #include <sys/atomic.h>

 -bool bool_compare_and_swap_2(volatile uint16_t *, uint16_t, uint16_t, ...)
 +bool bool_compare_and_swap_2(volatile int16_t *, int16_t, int16_t, ...)
      asm("__sync_bool_compare_and_swap_2");

  bool
 -bool_compare_and_swap_2(volatile uint16_t *addr, uint16_t oldval,
 -	uint16_t newval, ...)
 +bool_compare_and_swap_2(volatile int16_t *addr, int16_t oldval,
 +	int16_t newval, ...)
  {
 -	return atomic_cas_16(addr, oldval, newval) == oldval;
 +	const uint16_t oldv = (uint16_t)oldval;
 +	const uint16_t newv = (uint16_t)newval;
 +
 +	return atomic_cas_16((volatile uint16_t *)addr, oldv, newv) == oldv;
  }
 Index: atomic_cas_32_cas.c
 ===================================================================
 RCS file: /cvsroot/src/common/lib/libc/atomic/atomic_cas_32_cas.c,v
 retrieving revision 1.2
 diff -u -p -r1.2 atomic_cas_32_cas.c
 --- atomic_cas_32_cas.c	8 Jan 2026 08:55:25 -0000	1.2
 +++ atomic_cas_32_cas.c	19 Mar 2026 19:44:18 -0000
 @@ -37,12 +37,15 @@

  #include <sys/atomic.h>

 -bool bool_compare_and_swap_4(volatile uint32_t *, uint32_t, uint32_t, ...)
 +bool bool_compare_and_swap_4(volatile int32_t *, int32_t, int32_t, ...)
      asm("__sync_bool_compare_and_swap_4");

  bool
 -bool_compare_and_swap_4(volatile uint32_t *addr, uint32_t oldval,
 -	uint32_t newval, ...)
 +bool_compare_and_swap_4(volatile int32_t *addr, int32_t oldval,
 +	int32_t newval, ...)
  {
 -	return atomic_cas_32(addr, oldval, newval) == oldval;
 +	const uint32_t oldv = (uint32_t)oldval;
 +	const uint32_t newv = (uint32_t)newval;
 +
 +	return atomic_cas_32((volatile uint32_t *)addr, oldv, newv) == oldv;
  }
 Index: atomic_cas_64_cas.c
 ===================================================================
 RCS file: /cvsroot/src/common/lib/libc/atomic/atomic_cas_64_cas.c,v
 retrieving revision 1.3
 diff -u -p -r1.3 atomic_cas_64_cas.c
 --- atomic_cas_64_cas.c	8 Jan 2026 08:55:25 -0000	1.3
 +++ atomic_cas_64_cas.c	19 Mar 2026 19:44:18 -0000
 @@ -39,14 +39,17 @@

  #ifdef __HAVE_ATOMIC64_OPS

 -bool bool_compare_and_swap_8(volatile uint64_t *, uint64_t, uint64_t, ...)
 +bool bool_compare_and_swap_8(volatile int64_t *, int64_t, int64_t, ...)
      asm("__sync_bool_compare_and_swap_8");

  bool
 -bool_compare_and_swap_8(volatile uint64_t *addr, uint64_t oldval,
 -	uint64_t newval, ...)
 +bool_compare_and_swap_8(volatile int64_t *addr, int64_t oldval,
 +	int64_t newval, ...)
  {
 -	return atomic_cas_64(addr, oldval, newval) == oldval;
 +	const uin64_t oldv = (uint64_t)oldval;
 +	const uin64_t newv = (uint64_t)newval;
 +
 +	return atomic_cas_64((volatile uint64 *)addr, oldv, newv) == oldv;
  }

  #endif
 Index: atomic_cas_8_cas.c
 ===================================================================
 RCS file: /cvsroot/src/common/lib/libc/atomic/atomic_cas_8_cas.c,v
 retrieving revision 1.3
 diff -u -p -r1.3 atomic_cas_8_cas.c
 --- atomic_cas_8_cas.c	21 Feb 2014 16:06:48 -0000	1.3
 +++ atomic_cas_8_cas.c	19 Mar 2026 19:44:18 -0000
 @@ -35,13 +35,17 @@
  #include <stdbool.h>
  #endif
  #include <sys/atomic.h>
 +#include <stdarg.h>

 -bool bool_compare_and_swap_1(volatile uint8_t *, uint8_t, uint8_t, ...)
 +bool bool_compare_and_swap_1(volatile int8_t *, int8_t, int8_t, ...)
      asm("__sync_bool_compare_and_swap_1");

  bool
 -bool_compare_and_swap_1(volatile uint8_t *addr, uint8_t oldval,
 -	uint8_t newval, ...)
 +bool_compare_and_swap_1(volatile int8_t *addr, int8_t oldval,
 +	int8_t newval, ...)
  {
 -	return atomic_cas_8(addr, oldval, newval) == oldval;
 +	uint8_t oldv = (uint8_t)oldval;
 +	uint8_t newv = (uint8_t)newval;
 +
 +	return atomic_cas_8((volatile uint8_t *)addr, oldv, newv) == oldv;
  }
 Index: atomic_cas_by_cas32.c
 ===================================================================
 RCS file: /cvsroot/src/common/lib/libc/atomic/atomic_cas_by_cas32.c,v
 retrieving revision 1.4
 diff -u -p -r1.4 atomic_cas_by_cas32.c
 --- atomic_cas_by_cas32.c	3 Sep 2014 19:30:47 -0000	1.4
 +++ atomic_cas_by_cas32.c	19 Mar 2026 19:44:18 -0000
 @@ -64,8 +64,6 @@ _atomic_cas_16(volatile uint16_t *addr, 
  	return old;
  }

 -crt_alias(__sync_val_compare_and_swap_2,_atomic_cas_16)
 -
  uint8_t
  _atomic_cas_8(volatile uint8_t *addr, uint8_t old, uint8_t new)
  {
 @@ -87,5 +85,3 @@ _atomic_cas_8(volatile uint8_t *addr, ui

  	return old;
  }
 -
 -crt_alias(__sync_val_compare_and_swap_1,_atomic_cas_8)
 Index: atomic_init_testset.c
 ===================================================================
 RCS file: /cvsroot/src/common/lib/libc/atomic/atomic_init_testset.c,v
 retrieving revision 1.21
 diff -u -p -r1.21 atomic_init_testset.c
 --- atomic_init_testset.c	9 Jan 2026 08:44:57 -0000	1.21
 +++ atomic_init_testset.c	19 Mar 2026 19:44:18 -0000
 @@ -345,8 +345,43 @@ __strong_alias(_atomic_cas_ptr_ni,_atomi
  atomic_op_alias(atomic_cas_64,_atomic_cas_64)
  atomic_op_alias(atomic_cas_64_ni,_atomic_cas_64)
  __strong_alias(_atomic_cas_64_ni,_atomic_cas_64)
 -crt_alias(__sync_val_compare_and_swap_8,_atomic_cas_64)
 +
 +int64_t sync_val_compare_and_swap_8(volatile int64_t *addr, int64_t old, int64_t new)
 +    asm("__sync_val_compare_and_swap_8");
 +
 +int64_t
 +sync_val_compare_and_swap_8(volatile int64_t *addr, int64_t old, int64_t new)
 +{
 +	const uint64_t oldv = (uint64_t)old;
 +	const uint64_t newv = (uint64_t)new;
 +
 +	return _atomic_cas_64((volatile uint64_t *)addr, oldv, newv);
 +}
 +
  #endif
  crt_alias(__sync_val_compare_and_swap_4,_atomic_cas_32)
 -crt_alias(__sync_val_compare_and_swap_2,_atomic_cas_16)
 -crt_alias(__sync_val_compare_and_swap_1,_atomic_cas_8)
 +
 +
 +int16_t sync_val_compare_and_swap_2(volatile int16_t *addr, int16_t old, int16_t new)
 +    asm("__sync_val_compare_and_swap_2");
 +
 +int16_t
 +sync_val_compare_and_swap_2(volatile int16_t *addr, int16_t old, int16_t new)
 +{
 +	const uint16_t oldv = (uint16_t)old;
 +	const uint16_t newv = (uint16_t)new;
 +
 +	return _atomic_cas_16((volatile uint16_t *)addr, oldv, newv);
 +}
 +
 +int8_t sync_val_compare_and_swap_1(volatile int8_t *addr, int8_t old, int8_t new)
 +    asm("__sync_val_compare_and_swap_1");
 +
 +int8_t
 +sync_val_compare_and_swap_1(volatile int8_t *addr, int8_t old, int8_t new)
 +{
 +	const uint8_t oldv = (uint8_t)old;
 +	const uint8_t newv = (uint8_t)new;
 +
 +	return _atomic_cas_8((volatile uint8_t *)addr, oldv, newv);
 +}

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2026 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.