Home | History | Annotate | Line # | Download | only in atomic
      1 /*	$NetBSD: t___sync_compare_and_swap.c,v 1.3 2025/04/25 12:11:13 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2019 Tetsuya Isaki. All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __RCSID("$NetBSD: t___sync_compare_and_swap.c,v 1.3 2025/04/25 12:11:13 riastradh Exp $");
     30 
     31 #include <atf-c.h>
     32 #include <inttypes.h>
     33 #include <machine/types.h>	// for __HAVE_ATOMIC64_OPS
     34 
     35 #if defined __arm__ && __ARM_ARCH <= 5
     36 #define	pr56839_xfail							      \
     37 	atf_tc_expect_fail("PR port-arm/56839:"				      \
     38 	    "GCC emits wrong codes for compare_and_swap_1 bultins"	      \
     39 	    " on armv5 (el & eb)")
     40 #else
     41 #define	pr56839_xfail	__nothing
     42 #endif
     43 
     44 /*
     45  * These tests don't examine the atomicity.
     46  */
     47 
     48 /* XXX
     49  * Depending on a combination of arch and compiler, __sync_* is
     50  * implemented as compiler's builtin function.  In that case, even
     51  * if libc exports the function symbol, it is not used.  As a result
     52  * this tests will examine compiler's builtin functions.
     53  * It's better to run only when target is actually in libc.
     54  */
     55 
     56 #define OLDVAL (0x1122334455667788UL)
     57 #define NEWVAL (0x8090a0b0c0d0e0f0UL)
     58 
     59 #define atf_sync_bool(NAME, TYPE, FMT, XFAIL) \
     60 ATF_TC(NAME); \
     61 ATF_TC_HEAD(NAME, tc) \
     62 { \
     63 	atf_tc_set_md_var(tc, "descr", #NAME); \
     64 } \
     65 ATF_TC_BODY(NAME, tc) \
     66 { \
     67 	volatile TYPE val; \
     68 	TYPE oldval; \
     69 	TYPE newval; \
     70 	TYPE expval; \
     71 	bool expres; \
     72 	bool res; \
     73 	XFAIL; \
     74 	/* If successful */ \
     75 	val = (TYPE)OLDVAL; \
     76 	oldval = (TYPE)OLDVAL; \
     77 	newval = (TYPE)NEWVAL; \
     78 	expval = (TYPE)NEWVAL; \
     79 	expres = true; \
     80 	res = NAME(&val, oldval, newval); \
     81 	ATF_REQUIRE_MSG(val == expval, \
     82 	    "successful case: val expects 0x%" FMT " but 0x%" FMT, expval, val); \
     83 	ATF_REQUIRE_MSG(res == expres, \
     84 	    "successful case: res expects %d but %d", expres, res); \
     85 	/* If failure */ \
     86 	val = (TYPE)OLDVAL; \
     87 	oldval = (TYPE)(OLDVAL + 1); \
     88 	newval = (TYPE)NEWVAL; \
     89 	expval = (TYPE)OLDVAL; \
     90 	expres = false; \
     91 	res = NAME(&val, oldval, newval); \
     92 	ATF_REQUIRE_MSG(val == expval, \
     93 	    "failure case: val expects 0x%" FMT " but 0x%" FMT, expval, val); \
     94 	ATF_REQUIRE_MSG(res == expres, \
     95 	    "failure case: res expects %d but %d", expres, res); \
     96 }
     97 
     98 atf_sync_bool(__sync_bool_compare_and_swap_1, uint8_t,  PRIx8, pr56839_xfail);
     99 atf_sync_bool(__sync_bool_compare_and_swap_2, uint16_t, PRIx16, __nothing);
    100 atf_sync_bool(__sync_bool_compare_and_swap_4, uint32_t, PRIx32, __nothing);
    101 #ifdef __HAVE_ATOMIC64_OPS
    102 atf_sync_bool(__sync_bool_compare_and_swap_8, uint64_t, PRIx64, __nothing);
    103 #endif
    104 
    105 #if _BYTE_ORDER == _LITTLE_ENDIAN
    106 #  define LSB	0
    107 #  define MSB	1
    108 #elif _BYTE_ORDER == _BIG_ENDIAN
    109 #  define LSB	1
    110 #  define MSB	0
    111 #else
    112 #  error Unknown byte order!
    113 #endif
    114 
    115 #define atf_sync_bool_subword(NAME, SUBWIDTH, SUBTYPE, TYPE, SUBFMT, FMT, XFAIL) \
    116 ATF_TC(NAME##_subword); \
    117 ATF_TC_HEAD(NAME##_subword, tc) \
    118 { \
    119 	atf_tc_set_md_var(tc, "descr", "subword " #NAME); \
    120 } \
    121 ATF_TC_BODY(NAME##_subword, tc) \
    122 { \
    123 	volatile union { \
    124 		TYPE word; \
    125 		SUBTYPE subword[2]; \
    126 	} val; \
    127 	XFAIL; \
    128 	/* If successful */ \
    129 	val.subword[LSB] = -1; \
    130 	val.subword[MSB] = 123; \
    131 	ATF_CHECK(NAME(&val.subword[LSB], /*old*/-1, /*new*/-2)); \
    132 	ATF_CHECK_EQ_MSG(val.subword[LSB], (SUBTYPE)-2, \
    133 	    "val.subword[LSB] = 0x%" SUBFMT, val.subword[LSB]); \
    134 	ATF_CHECK_EQ_MSG(val.subword[MSB], 123, \
    135 	    "val.subword[MSB] = 0x%" SUBFMT, val.subword[MSB]); \
    136 	ATF_CHECK_EQ_MSG(val.word, \
    137 	    ((TYPE)123 << (SUBWIDTH)) | (TYPE)(SUBTYPE)-2, \
    138 	    "val.word = 0x%" FMT, val.word); \
    139 	/* If failed */ \
    140 	val.subword[LSB] = -3; \
    141 	val.subword[MSB] = 45; \
    142 	ATF_CHECK(!NAME(&val.subword[LSB], /*old*/-1, /*new*/-2)); \
    143 	ATF_CHECK_EQ_MSG(val.subword[LSB], (SUBTYPE)-3, \
    144 	    "val.subword[LSB] = 0x%" SUBFMT, val.subword[LSB]); \
    145 	ATF_CHECK_EQ_MSG(val.subword[MSB], 45, \
    146 	    "val.subword[MSB] = 0x%" SUBFMT, val.subword[MSB]); \
    147 	ATF_CHECK_EQ_MSG(val.word, \
    148 	    ((TYPE)45 << (SUBWIDTH)) | (TYPE)(SUBTYPE)-3, \
    149 	    "val.word = 0x%" FMT, val.word); \
    150 }
    151 
    152 atf_sync_bool_subword(__sync_bool_compare_and_swap_1, 8, uint8_t, uint16_t,
    153     PRIx8, PRIx16, pr56839_xfail);
    154 atf_sync_bool_subword(__sync_bool_compare_and_swap_2, 16, uint16_t, uint32_t,
    155     PRIx16, PRIx32, pr56839_xfail);
    156 atf_sync_bool_subword(__sync_bool_compare_and_swap_4, 32, uint32_t, uint64_t,
    157     PRIx32, PRIx64, __nothing);
    158 
    159 #define atf_sync_val(NAME, TYPE, FMT, XFAIL) \
    160 ATF_TC(NAME); \
    161 ATF_TC_HEAD(NAME, tc) \
    162 { \
    163 	atf_tc_set_md_var(tc, "descr", #NAME); \
    164 } \
    165 ATF_TC_BODY(NAME, tc) \
    166 { \
    167 	volatile TYPE val; \
    168 	TYPE oldval; \
    169 	TYPE newval; \
    170 	TYPE expval; \
    171 	TYPE expres; \
    172 	TYPE res; \
    173 	XFAIL; \
    174 	/* If successful */ \
    175 	val = (TYPE)OLDVAL; \
    176 	oldval = (TYPE)OLDVAL; \
    177 	newval = (TYPE)NEWVAL; \
    178 	expval = (TYPE)NEWVAL; \
    179 	expres = (TYPE)OLDVAL; \
    180 	res = NAME(&val, oldval, newval); \
    181 	ATF_REQUIRE_MSG(val == expval, \
    182 	    "successful case: val expects 0x%" FMT " but 0x%" FMT, expval, val); \
    183 	ATF_REQUIRE_MSG(res == expres, \
    184 	    "successful case: res expects 0x%" FMT " but 0x%" FMT, expres, res); \
    185 	/* If failure */ \
    186 	val = (TYPE)OLDVAL; \
    187 	oldval = (TYPE)(OLDVAL + 1); \
    188 	newval = (TYPE)NEWVAL; \
    189 	expval = (TYPE)OLDVAL; \
    190 	expres = (TYPE)OLDVAL; \
    191 	res = NAME(&val, oldval, newval); \
    192 	ATF_REQUIRE_MSG(val == expval, \
    193 	    "failure case: val expects 0x%" FMT " but 0x%" FMT, expval, val); \
    194 	ATF_REQUIRE_MSG(res == expres, \
    195 	    "failure case: res expects 0x%" FMT " but 0x%" FMT, expres, res); \
    196 }
    197 
    198 atf_sync_val(__sync_val_compare_and_swap_1, uint8_t,  PRIx8, pr56839_xfail);
    199 atf_sync_val(__sync_val_compare_and_swap_2, uint16_t, PRIx16, __nothing);
    200 atf_sync_val(__sync_val_compare_and_swap_4, uint32_t, PRIx32, __nothing);
    201 #ifdef __HAVE_ATOMIC64_OPS
    202 atf_sync_val(__sync_val_compare_and_swap_8, uint64_t, PRIx64, __nothing);
    203 #endif
    204 
    205 #define atf_sync_val_subword(NAME, SUBWIDTH, SUBTYPE, TYPE, SUBFMT, FMT, XFAIL) \
    206 ATF_TC(NAME##_subword); \
    207 ATF_TC_HEAD(NAME##_subword, tc) \
    208 { \
    209 	atf_tc_set_md_var(tc, "descr", "subword " #NAME); \
    210 } \
    211 ATF_TC_BODY(NAME##_subword, tc) \
    212 { \
    213 	volatile union { \
    214 		TYPE word; \
    215 		SUBTYPE subword[2]; \
    216 	} val; \
    217 	SUBTYPE rval; \
    218 	XFAIL; \
    219 	/* If successful */ \
    220 	val.subword[LSB] = -1; \
    221 	val.subword[MSB] = 123; \
    222 	ATF_CHECK_EQ_MSG((rval = NAME(&val.subword[LSB], \
    223 		/*old*/-1, /*new*/-2)), (SUBTYPE)-1, \
    224 	    "expected 0x%" SUBFMT ", got 0x%" SUBFMT, \
    225 	    (SUBTYPE)-1, rval); \
    226 	ATF_CHECK_EQ_MSG(val.subword[LSB], (SUBTYPE)-2, \
    227 	    "val.subword[LSB] = 0x%" SUBFMT, val.subword[LSB]); \
    228 	ATF_CHECK_EQ_MSG(val.subword[MSB], 123, \
    229 	    "val.subword[MSB] = 0x%" SUBFMT, val.subword[MSB]); \
    230 	ATF_CHECK_EQ_MSG(val.word, \
    231 	    ((TYPE)123 << (SUBWIDTH)) | (TYPE)(SUBTYPE)-2, \
    232 	    "val.word = 0x%" FMT, val.word); \
    233 	/* If failed */ \
    234 	val.subword[LSB] = -3; \
    235 	val.subword[MSB] = 45; \
    236 	ATF_CHECK_EQ_MSG((rval = NAME(&val.subword[LSB], \
    237 		/*old*/-1, /*new*/-2)), (SUBTYPE)-3, \
    238 	    "expected 0x%" SUBFMT ", got 0x%" SUBFMT, \
    239 	    (SUBTYPE)-3, rval); \
    240 	ATF_CHECK_EQ_MSG(val.subword[LSB], (SUBTYPE)-3, \
    241 	    "val.subword[LSB] = 0x%" SUBFMT, val.subword[LSB]); \
    242 	ATF_CHECK_EQ_MSG(val.subword[MSB], 45, \
    243 	    "val.subword[MSB] = 0x%" SUBFMT, val.subword[MSB]); \
    244 	ATF_CHECK_EQ_MSG(val.word, \
    245 	    ((TYPE)45 << (SUBWIDTH)) | (TYPE)(SUBTYPE)-3, \
    246 	    "val.word = 0x%" FMT, val.word); \
    247 }
    248 
    249 atf_sync_val_subword(__sync_val_compare_and_swap_1, 8, uint8_t, uint16_t,
    250     PRIx8, PRIx16, pr56839_xfail);
    251 atf_sync_val_subword(__sync_val_compare_and_swap_2, 16, uint16_t, uint32_t,
    252     PRIx16, PRIx32, pr56839_xfail);
    253 atf_sync_val_subword(__sync_val_compare_and_swap_4, 32, uint32_t, uint64_t,
    254     PRIx32, PRIx64, __nothing);
    255 
    256 ATF_TP_ADD_TCS(tp)
    257 {
    258 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_1);
    259 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_2);
    260 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_4);
    261 #ifdef __HAVE_ATOMIC64_OPS
    262 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_8);
    263 #endif
    264 
    265 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_1_subword);
    266 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_2_subword);
    267 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_4_subword);
    268 
    269 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_1);
    270 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_2);
    271 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_4);
    272 #ifdef __HAVE_ATOMIC64_OPS
    273 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_8);
    274 #endif
    275 
    276 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_1_subword);
    277 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_2_subword);
    278 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_4_subword);
    279 
    280 	return atf_no_error();
    281 }
    282