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