1;; Machine description for LoongArch atomic operations. 2;; Copyright (C) 2021-2022 Free Software Foundation, Inc. 3;; Contributed by Loongson Ltd. 4;; Based on MIPS and RISC-V target for GNU compiler. 5 6;; This file is part of GCC. 7 8;; GCC is free software; you can redistribute it and/or modify 9;; it under the terms of the GNU General Public License as published by 10;; the Free Software Foundation; either version 3, or (at your option) 11;; any later version. 12 13;; GCC is distributed in the hope that it will be useful, 14;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16;; GNU General Public License for more details. 17 18;; You should have received a copy of the GNU General Public License 19;; along with GCC; see the file COPYING3. If not see 20;; <http://www.gnu.org/licenses/>. 21 22(define_c_enum "unspec" [ 23 UNSPEC_COMPARE_AND_SWAP 24 UNSPEC_COMPARE_AND_SWAP_ADD 25 UNSPEC_COMPARE_AND_SWAP_SUB 26 UNSPEC_COMPARE_AND_SWAP_AND 27 UNSPEC_COMPARE_AND_SWAP_XOR 28 UNSPEC_COMPARE_AND_SWAP_OR 29 UNSPEC_COMPARE_AND_SWAP_NAND 30 UNSPEC_SYNC_OLD_OP 31 UNSPEC_SYNC_EXCHANGE 32 UNSPEC_ATOMIC_STORE 33 UNSPEC_MEMORY_BARRIER 34]) 35 36(define_code_iterator any_atomic [plus ior xor and]) 37(define_code_attr atomic_optab 38 [(plus "add") (ior "or") (xor "xor") (and "and")]) 39 40;; This attribute gives the format suffix for atomic memory operations. 41(define_mode_attr amo [(SI "w") (DI "d")]) 42 43;; <amop> expands to the name of the atomic operand that implements a 44;; particular code. 45(define_code_attr amop [(ior "or") (xor "xor") (and "and") (plus "add")]) 46 47;; Memory barriers. 48 49(define_expand "mem_thread_fence" 50 [(match_operand:SI 0 "const_int_operand" "")] ;; model 51 "" 52{ 53 if (INTVAL (operands[0]) != MEMMODEL_RELAXED) 54 { 55 rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); 56 MEM_VOLATILE_P (mem) = 1; 57 emit_insn (gen_mem_thread_fence_1 (mem, operands[0])); 58 } 59 DONE; 60}) 61 62;; Until the LoongArch memory model (hence its mapping from C++) is finalized, 63;; conservatively emit a full FENCE. 64(define_insn "mem_thread_fence_1" 65 [(set (match_operand:BLK 0 "" "") 66 (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER)) 67 (match_operand:SI 1 "const_int_operand" "")] ;; model 68 "" 69 "dbar\t0") 70 71;; Atomic memory operations. 72 73;; Implement atomic stores with amoswap. Fall back to fences for atomic loads. 74(define_insn "atomic_store<mode>" 75 [(set (match_operand:GPR 0 "memory_operand" "+ZB") 76 (unspec_volatile:GPR 77 [(match_operand:GPR 1 "reg_or_0_operand" "rJ") 78 (match_operand:SI 2 "const_int_operand")] ;; model 79 UNSPEC_ATOMIC_STORE))] 80 "" 81 "amswap%A2.<amo>\t$zero,%z1,%0" 82 [(set (attr "length") (const_int 8))]) 83 84(define_insn "atomic_<atomic_optab><mode>" 85 [(set (match_operand:GPR 0 "memory_operand" "+ZB") 86 (unspec_volatile:GPR 87 [(any_atomic:GPR (match_dup 0) 88 (match_operand:GPR 1 "reg_or_0_operand" "rJ")) 89 (match_operand:SI 2 "const_int_operand")] ;; model 90 UNSPEC_SYNC_OLD_OP))] 91 "" 92 "am<amop>%A2.<amo>\t$zero,%z1,%0" 93 [(set (attr "length") (const_int 8))]) 94 95(define_insn "atomic_fetch_<atomic_optab><mode>" 96 [(set (match_operand:GPR 0 "register_operand" "=&r") 97 (match_operand:GPR 1 "memory_operand" "+ZB")) 98 (set (match_dup 1) 99 (unspec_volatile:GPR 100 [(any_atomic:GPR (match_dup 1) 101 (match_operand:GPR 2 "reg_or_0_operand" "rJ")) 102 (match_operand:SI 3 "const_int_operand")] ;; model 103 UNSPEC_SYNC_OLD_OP))] 104 "" 105 "am<amop>%A3.<amo>\t%0,%z2,%1" 106 [(set (attr "length") (const_int 8))]) 107 108(define_insn "atomic_exchange<mode>" 109 [(set (match_operand:GPR 0 "register_operand" "=&r") 110 (unspec_volatile:GPR 111 [(match_operand:GPR 1 "memory_operand" "+ZB") 112 (match_operand:SI 3 "const_int_operand")] ;; model 113 UNSPEC_SYNC_EXCHANGE)) 114 (set (match_dup 1) 115 (match_operand:GPR 2 "register_operand" "r"))] 116 "" 117 "amswap%A3.<amo>\t%0,%z2,%1" 118 [(set (attr "length") (const_int 8))]) 119 120(define_insn "atomic_cas_value_strong<mode>" 121 [(set (match_operand:GPR 0 "register_operand" "=&r") 122 (match_operand:GPR 1 "memory_operand" "+ZC")) 123 (set (match_dup 1) 124 (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ") 125 (match_operand:GPR 3 "reg_or_0_operand" "rJ") 126 (match_operand:SI 4 "const_int_operand") ;; mod_s 127 (match_operand:SI 5 "const_int_operand")] ;; mod_f 128 UNSPEC_COMPARE_AND_SWAP)) 129 (clobber (match_scratch:GPR 6 "=&r"))] 130 "" 131{ 132 output_asm_insn ("1:", operands); 133 output_asm_insn ("ll.<amo>\t%0,%1", operands); 134 135 /* Like the test case atomic-cas-int.C, in loongarch64, O1 and higher, the 136 return value of the val_without_const_folding will not be truncated and 137 will be passed directly to the function compare_exchange_strong. 138 However, the instruction 'bne' does not distinguish between 32-bit and 139 64-bit operations. so if the upper 32 bits of the register are not 140 extended by the 32nd bit symbol, then the comparison may not be valid 141 here. This will affect the result of the operation. */ 142 143 if (TARGET_64BIT && REG_P (operands[2]) 144 && GET_MODE (operands[2]) == SImode) 145 { 146 output_asm_insn ("addi.w\t%6,%2,0", operands); 147 output_asm_insn ("bne\t%0,%6,2f", operands); 148 } 149 else 150 output_asm_insn ("bne\t%0,%z2,2f", operands); 151 152 output_asm_insn ("or%i3\t%6,$zero,%3", operands); 153 output_asm_insn ("sc.<amo>\t%6,%1", operands); 154 output_asm_insn ("beqz\t%6,1b", operands); 155 output_asm_insn ("b\t3f", operands); 156 output_asm_insn ("2:", operands); 157 output_asm_insn ("%G5", operands); 158 output_asm_insn ("3:", operands); 159 160 return ""; 161} 162 [(set (attr "length") 163 (if_then_else 164 (and (match_test "GET_MODE (operands[2]) == SImode") 165 (match_test "REG_P (operands[2])")) 166 (const_int 32) 167 (const_int 28)))]) 168 169(define_expand "atomic_compare_and_swap<mode>" 170 [(match_operand:SI 0 "register_operand" "") ;; bool output 171 (match_operand:GPR 1 "register_operand" "") ;; val output 172 (match_operand:GPR 2 "memory_operand" "") ;; memory 173 (match_operand:GPR 3 "reg_or_0_operand" "") ;; expected value 174 (match_operand:GPR 4 "reg_or_0_operand" "") ;; desired value 175 (match_operand:SI 5 "const_int_operand" "") ;; is_weak 176 (match_operand:SI 6 "const_int_operand" "") ;; mod_s 177 (match_operand:SI 7 "const_int_operand" "")] ;; mod_f 178 "" 179{ 180 emit_insn (gen_atomic_cas_value_strong<mode> (operands[1], operands[2], 181 operands[3], operands[4], 182 operands[6], operands[7])); 183 184 rtx compare = operands[1]; 185 if (operands[3] != const0_rtx) 186 { 187 rtx difference = gen_rtx_MINUS (<MODE>mode, operands[1], operands[3]); 188 compare = gen_reg_rtx (<MODE>mode); 189 emit_insn (gen_rtx_SET (compare, difference)); 190 } 191 192 if (word_mode != <MODE>mode) 193 { 194 rtx reg = gen_reg_rtx (word_mode); 195 emit_insn (gen_rtx_SET (reg, gen_rtx_SIGN_EXTEND (word_mode, compare))); 196 compare = reg; 197 } 198 199 emit_insn (gen_rtx_SET (operands[0], 200 gen_rtx_EQ (SImode, compare, const0_rtx))); 201 DONE; 202}) 203 204(define_expand "atomic_test_and_set" 205 [(match_operand:QI 0 "register_operand" "") ;; bool output 206 (match_operand:QI 1 "memory_operand" "+ZB") ;; memory 207 (match_operand:SI 2 "const_int_operand" "")] ;; model 208 "" 209{ 210 /* We have no QImode atomics, so use the address LSBs to form a mask, 211 then use an aligned SImode atomic. */ 212 rtx result = operands[0]; 213 rtx mem = operands[1]; 214 rtx model = operands[2]; 215 rtx addr = force_reg (Pmode, XEXP (mem, 0)); 216 rtx tmp_reg = gen_reg_rtx (Pmode); 217 rtx zero_reg = gen_rtx_REG (Pmode, 0); 218 219 rtx aligned_addr = gen_reg_rtx (Pmode); 220 emit_move_insn (tmp_reg, gen_rtx_PLUS (Pmode, zero_reg, GEN_INT (-4))); 221 emit_move_insn (aligned_addr, gen_rtx_AND (Pmode, addr, tmp_reg)); 222 223 rtx aligned_mem = change_address (mem, SImode, aligned_addr); 224 set_mem_alias_set (aligned_mem, 0); 225 226 rtx offset = gen_reg_rtx (SImode); 227 emit_move_insn (offset, gen_rtx_AND (SImode, gen_lowpart (SImode, addr), 228 GEN_INT (3))); 229 230 rtx tmp = gen_reg_rtx (SImode); 231 emit_move_insn (tmp, GEN_INT (1)); 232 233 rtx shmt = gen_reg_rtx (SImode); 234 emit_move_insn (shmt, gen_rtx_ASHIFT (SImode, offset, GEN_INT (3))); 235 236 rtx word = gen_reg_rtx (SImode); 237 emit_move_insn (word, gen_rtx_ASHIFT (SImode, tmp, shmt)); 238 239 tmp = gen_reg_rtx (SImode); 240 emit_insn (gen_atomic_fetch_orsi (tmp, aligned_mem, word, model)); 241 242 emit_move_insn (gen_lowpart (SImode, result), 243 gen_rtx_LSHIFTRT (SImode, tmp, shmt)); 244 DONE; 245}) 246 247(define_insn "atomic_cas_value_cmp_and_7_<mode>" 248 [(set (match_operand:GPR 0 "register_operand" "=&r") 249 (match_operand:GPR 1 "memory_operand" "+ZC")) 250 (set (match_dup 1) 251 (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ") 252 (match_operand:GPR 3 "reg_or_0_operand" "rJ") 253 (match_operand:GPR 4 "reg_or_0_operand" "rJ") 254 (match_operand:GPR 5 "reg_or_0_operand" "rJ") 255 (match_operand:SI 6 "const_int_operand")] ;; model 256 UNSPEC_COMPARE_AND_SWAP)) 257 (clobber (match_scratch:GPR 7 "=&r"))] 258 "" 259{ 260 return "1:\\n\\t" 261 "ll.<amo>\\t%0,%1\\n\\t" 262 "and\\t%7,%0,%2\\n\\t" 263 "bne\\t%7,%z4,2f\\n\\t" 264 "and\\t%7,%0,%z3\\n\\t" 265 "or%i5\\t%7,%7,%5\\n\\t" 266 "sc.<amo>\\t%7,%1\\n\\t" 267 "beq\\t$zero,%7,1b\\n\\t" 268 "b\\t3f\\n\\t" 269 "2:\\n\\t" 270 "%G6\\n\\t" 271 "3:\\n\\t"; 272} 273 [(set (attr "length") (const_int 36))]) 274 275(define_expand "atomic_compare_and_swap<mode>" 276 [(match_operand:SI 0 "register_operand" "") ;; bool output 277 (match_operand:SHORT 1 "register_operand" "") ;; val output 278 (match_operand:SHORT 2 "memory_operand" "") ;; memory 279 (match_operand:SHORT 3 "reg_or_0_operand" "") ;; expected value 280 (match_operand:SHORT 4 "reg_or_0_operand" "") ;; desired value 281 (match_operand:SI 5 "const_int_operand" "") ;; is_weak 282 (match_operand:SI 6 "const_int_operand" "") ;; mod_s 283 (match_operand:SI 7 "const_int_operand" "")] ;; mod_f 284 "" 285{ 286 union loongarch_gen_fn_ptrs generator; 287 generator.fn_7 = gen_atomic_cas_value_cmp_and_7_si; 288 loongarch_expand_atomic_qihi (generator, operands[1], operands[2], 289 operands[3], operands[4], operands[7]); 290 291 rtx compare = operands[1]; 292 if (operands[3] != const0_rtx) 293 { 294 machine_mode mode = GET_MODE (operands[3]); 295 rtx op1 = convert_modes (SImode, mode, operands[1], true); 296 rtx op3 = convert_modes (SImode, mode, operands[3], true); 297 rtx difference = gen_rtx_MINUS (SImode, op1, op3); 298 compare = gen_reg_rtx (SImode); 299 emit_insn (gen_rtx_SET (compare, difference)); 300 } 301 302 if (word_mode != <MODE>mode) 303 { 304 rtx reg = gen_reg_rtx (word_mode); 305 emit_insn (gen_rtx_SET (reg, gen_rtx_SIGN_EXTEND (word_mode, compare))); 306 compare = reg; 307 } 308 309 emit_insn (gen_rtx_SET (operands[0], 310 gen_rtx_EQ (SImode, compare, const0_rtx))); 311 DONE; 312}) 313 314(define_insn "atomic_cas_value_add_7_<mode>" 315 [(set (match_operand:GPR 0 "register_operand" "=&r") ;; res 316 (match_operand:GPR 1 "memory_operand" "+ZC")) 317 (set (match_dup 1) 318 (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ") ;; mask 319 (match_operand:GPR 3 "reg_or_0_operand" "rJ") ;; inverted_mask 320 (match_operand:GPR 4 "reg_or_0_operand" "rJ") ;; old val 321 (match_operand:GPR 5 "reg_or_0_operand" "rJ") ;; new val 322 (match_operand:SI 6 "const_int_operand")] ;; model 323 UNSPEC_COMPARE_AND_SWAP_ADD)) 324 (clobber (match_scratch:GPR 7 "=&r")) 325 (clobber (match_scratch:GPR 8 "=&r"))] 326 "" 327{ 328 return "1:\\n\\t" 329 "ll.<amo>\\t%0,%1\\n\\t" 330 "and\\t%7,%0,%3\\n\\t" 331 "add.w\\t%8,%0,%z5\\n\\t" 332 "and\\t%8,%8,%z2\\n\\t" 333 "or%i8\\t%7,%7,%8\\n\\t" 334 "sc.<amo>\\t%7,%1\\n\\t" 335 "beq\\t$zero,%7,1b"; 336} 337 338 [(set (attr "length") (const_int 28))]) 339 340(define_insn "atomic_cas_value_sub_7_<mode>" 341 [(set (match_operand:GPR 0 "register_operand" "=&r") ;; res 342 (match_operand:GPR 1 "memory_operand" "+ZC")) 343 (set (match_dup 1) 344 (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ") ;; mask 345 (match_operand:GPR 3 "reg_or_0_operand" "rJ") ;; inverted_mask 346 (match_operand:GPR 4 "reg_or_0_operand" "rJ") ;; old val 347 (match_operand:GPR 5 "reg_or_0_operand" "rJ") ;; new val 348 (match_operand:SI 6 "const_int_operand")] ;; model 349 UNSPEC_COMPARE_AND_SWAP_SUB)) 350 (clobber (match_scratch:GPR 7 "=&r")) 351 (clobber (match_scratch:GPR 8 "=&r"))] 352 "" 353{ 354 return "1:\\n\\t" 355 "ll.<amo>\\t%0,%1\\n\\t" 356 "and\\t%7,%0,%3\\n\\t" 357 "sub.w\\t%8,%0,%z5\\n\\t" 358 "and\\t%8,%8,%z2\\n\\t" 359 "or%i8\\t%7,%7,%8\\n\\t" 360 "sc.<amo>\\t%7,%1\\n\\t" 361 "beq\\t$zero,%7,1b"; 362} 363 [(set (attr "length") (const_int 28))]) 364 365(define_insn "atomic_cas_value_and_7_<mode>" 366 [(set (match_operand:GPR 0 "register_operand" "=&r") ;; res 367 (match_operand:GPR 1 "memory_operand" "+ZC")) 368 (set (match_dup 1) 369 (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ") ;; mask 370 (match_operand:GPR 3 "reg_or_0_operand" "rJ") ;; inverted_mask 371 (match_operand:GPR 4 "reg_or_0_operand" "rJ") ;; old val 372 (match_operand:GPR 5 "reg_or_0_operand" "rJ") ;; new val 373 (match_operand:SI 6 "const_int_operand")] ;; model 374 UNSPEC_COMPARE_AND_SWAP_AND)) 375 (clobber (match_scratch:GPR 7 "=&r")) 376 (clobber (match_scratch:GPR 8 "=&r"))] 377 "" 378{ 379 return "1:\\n\\t" 380 "ll.<amo>\\t%0,%1\\n\\t" 381 "and\\t%7,%0,%3\\n\\t" 382 "and\\t%8,%0,%z5\\n\\t" 383 "and\\t%8,%8,%z2\\n\\t" 384 "or%i8\\t%7,%7,%8\\n\\t" 385 "sc.<amo>\\t%7,%1\\n\\t" 386 "beq\\t$zero,%7,1b"; 387} 388 [(set (attr "length") (const_int 28))]) 389 390(define_insn "atomic_cas_value_xor_7_<mode>" 391 [(set (match_operand:GPR 0 "register_operand" "=&r") ;; res 392 (match_operand:GPR 1 "memory_operand" "+ZC")) 393 (set (match_dup 1) 394 (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ") ;; mask 395 (match_operand:GPR 3 "reg_or_0_operand" "rJ") ;; inverted_mask 396 (match_operand:GPR 4 "reg_or_0_operand" "rJ") ;; old val 397 (match_operand:GPR 5 "reg_or_0_operand" "rJ") ;; new val 398 (match_operand:SI 6 "const_int_operand")] ;; model 399 UNSPEC_COMPARE_AND_SWAP_XOR)) 400 (clobber (match_scratch:GPR 7 "=&r")) 401 (clobber (match_scratch:GPR 8 "=&r"))] 402 "" 403{ 404 return "1:\\n\\t" 405 "ll.<amo>\\t%0,%1\\n\\t" 406 "and\\t%7,%0,%3\\n\\t" 407 "xor\\t%8,%0,%z5\\n\\t" 408 "and\\t%8,%8,%z2\\n\\t" 409 "or%i8\\t%7,%7,%8\\n\\t" 410 "sc.<amo>\\t%7,%1\\n\\t" 411 "beq\\t$zero,%7,1b"; 412} 413 414 [(set (attr "length") (const_int 28))]) 415 416(define_insn "atomic_cas_value_or_7_<mode>" 417 [(set (match_operand:GPR 0 "register_operand" "=&r") ;; res 418 (match_operand:GPR 1 "memory_operand" "+ZC")) 419 (set (match_dup 1) 420 (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ") ;; mask 421 (match_operand:GPR 3 "reg_or_0_operand" "rJ") ;; inverted_mask 422 (match_operand:GPR 4 "reg_or_0_operand" "rJ") ;; old val 423 (match_operand:GPR 5 "reg_or_0_operand" "rJ") ;; new val 424 (match_operand:SI 6 "const_int_operand")] ;; model 425 UNSPEC_COMPARE_AND_SWAP_OR)) 426 (clobber (match_scratch:GPR 7 "=&r")) 427 (clobber (match_scratch:GPR 8 "=&r"))] 428 "" 429{ 430 return "1:\\n\\t" 431 "ll.<amo>\\t%0,%1\\n\\t" 432 "and\\t%7,%0,%3\\n\\t" 433 "or\\t%8,%0,%z5\\n\\t" 434 "and\\t%8,%8,%z2\\n\\t" 435 "or%i8\\t%7,%7,%8\\n\\t" 436 "sc.<amo>\\t%7,%1\\n\\t" 437 "beq\\t$zero,%7,1b"; 438} 439 440 [(set (attr "length") (const_int 28))]) 441 442(define_insn "atomic_cas_value_nand_7_<mode>" 443 [(set (match_operand:GPR 0 "register_operand" "=&r") ;; res 444 (match_operand:GPR 1 "memory_operand" "+ZC")) 445 (set (match_dup 1) 446 (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ") ;; mask 447 (match_operand:GPR 3 "reg_or_0_operand" "rJ") ;; inverted_mask 448 (match_operand:GPR 4 "reg_or_0_operand" "rJ") ;; old val 449 (match_operand:GPR 5 "reg_or_0_operand" "rJ") ;; new val 450 (match_operand:SI 6 "const_int_operand")] ;; model 451 UNSPEC_COMPARE_AND_SWAP_NAND)) 452 (clobber (match_scratch:GPR 7 "=&r")) 453 (clobber (match_scratch:GPR 8 "=&r"))] 454 "" 455{ 456 return "1:\\n\\t" 457 "ll.<amo>\\t%0,%1\\n\\t" 458 "and\\t%7,%0,%3\\n\\t" 459 "and\\t%8,%0,%z5\\n\\t" 460 "xor\\t%8,%8,%z2\\n\\t" 461 "or%i8\\t%7,%7,%8\\n\\t" 462 "sc.<amo>\\t%7,%1\\n\\t" 463 "beq\\t$zero,%7,1b"; 464} 465 [(set (attr "length") (const_int 28))]) 466 467(define_insn "atomic_cas_value_exchange_7_<mode>" 468 [(set (match_operand:GPR 0 "register_operand" "=&r") 469 (match_operand:GPR 1 "memory_operand" "+ZC")) 470 (set (match_dup 1) 471 (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "rJ") 472 (match_operand:GPR 3 "reg_or_0_operand" "rJ") 473 (match_operand:GPR 4 "reg_or_0_operand" "rJ") 474 (match_operand:GPR 5 "reg_or_0_operand" "rJ") 475 (match_operand:SI 6 "const_int_operand")] ;; model 476 UNSPEC_SYNC_EXCHANGE)) 477 (clobber (match_scratch:GPR 7 "=&r"))] 478 "" 479{ 480 return "1:\\n\\t" 481 "ll.<amo>\\t%0,%1\\n\\t" 482 "and\\t%7,%0,%z3\\n\\t" 483 "or%i5\\t%7,%7,%5\\n\\t" 484 "sc.<amo>\\t%7,%1\\n\\t" 485 "beqz\\t%7,1b\\n\\t"; 486} 487 [(set (attr "length") (const_int 20))]) 488 489(define_expand "atomic_exchange<mode>" 490 [(set (match_operand:SHORT 0 "register_operand") 491 (unspec_volatile:SHORT 492 [(match_operand:SHORT 1 "memory_operand") 493 (match_operand:SI 3 "const_int_operand")] ;; model 494 UNSPEC_SYNC_EXCHANGE)) 495 (set (match_dup 1) 496 (match_operand:SHORT 2 "register_operand"))] 497 "" 498{ 499 union loongarch_gen_fn_ptrs generator; 500 generator.fn_7 = gen_atomic_cas_value_exchange_7_si; 501 loongarch_expand_atomic_qihi (generator, operands[0], operands[1], 502 const0_rtx, operands[2], operands[3]); 503 DONE; 504}) 505 506(define_expand "atomic_fetch_add<mode>" 507 [(set (match_operand:SHORT 0 "register_operand" "=&r") 508 (match_operand:SHORT 1 "memory_operand" "+ZB")) 509 (set (match_dup 1) 510 (unspec_volatile:SHORT 511 [(plus:SHORT (match_dup 1) 512 (match_operand:SHORT 2 "reg_or_0_operand" "rJ")) 513 (match_operand:SI 3 "const_int_operand")] ;; model 514 UNSPEC_SYNC_OLD_OP))] 515 "" 516{ 517 union loongarch_gen_fn_ptrs generator; 518 generator.fn_7 = gen_atomic_cas_value_add_7_si; 519 loongarch_expand_atomic_qihi (generator, operands[0], operands[1], 520 operands[1], operands[2], operands[3]); 521 DONE; 522}) 523 524(define_expand "atomic_fetch_sub<mode>" 525 [(set (match_operand:SHORT 0 "register_operand" "=&r") 526 (match_operand:SHORT 1 "memory_operand" "+ZB")) 527 (set (match_dup 1) 528 (unspec_volatile:SHORT 529 [(minus:SHORT (match_dup 1) 530 (match_operand:SHORT 2 "reg_or_0_operand" "rJ")) 531 (match_operand:SI 3 "const_int_operand")] ;; model 532 UNSPEC_SYNC_OLD_OP))] 533 "" 534{ 535 union loongarch_gen_fn_ptrs generator; 536 generator.fn_7 = gen_atomic_cas_value_sub_7_si; 537 loongarch_expand_atomic_qihi (generator, operands[0], operands[1], 538 operands[1], operands[2], operands[3]); 539 DONE; 540}) 541 542(define_expand "atomic_fetch_and<mode>" 543 [(set (match_operand:SHORT 0 "register_operand" "=&r") 544 (match_operand:SHORT 1 "memory_operand" "+ZB")) 545 (set (match_dup 1) 546 (unspec_volatile:SHORT 547 [(and:SHORT (match_dup 1) 548 (match_operand:SHORT 2 "reg_or_0_operand" "rJ")) 549 (match_operand:SI 3 "const_int_operand")] ;; model 550 UNSPEC_SYNC_OLD_OP))] 551 "" 552{ 553 union loongarch_gen_fn_ptrs generator; 554 generator.fn_7 = gen_atomic_cas_value_and_7_si; 555 loongarch_expand_atomic_qihi (generator, operands[0], operands[1], 556 operands[1], operands[2], operands[3]); 557 DONE; 558}) 559 560(define_expand "atomic_fetch_xor<mode>" 561 [(set (match_operand:SHORT 0 "register_operand" "=&r") 562 (match_operand:SHORT 1 "memory_operand" "+ZB")) 563 (set (match_dup 1) 564 (unspec_volatile:SHORT 565 [(xor:SHORT (match_dup 1) 566 (match_operand:SHORT 2 "reg_or_0_operand" "rJ")) 567 (match_operand:SI 3 "const_int_operand")] ;; model 568 UNSPEC_SYNC_OLD_OP))] 569 "" 570{ 571 union loongarch_gen_fn_ptrs generator; 572 generator.fn_7 = gen_atomic_cas_value_xor_7_si; 573 loongarch_expand_atomic_qihi (generator, operands[0], operands[1], 574 operands[1], operands[2], operands[3]); 575 DONE; 576}) 577 578(define_expand "atomic_fetch_or<mode>" 579 [(set (match_operand:SHORT 0 "register_operand" "=&r") 580 (match_operand:SHORT 1 "memory_operand" "+ZB")) 581 (set (match_dup 1) 582 (unspec_volatile:SHORT 583 [(ior:SHORT (match_dup 1) 584 (match_operand:SHORT 2 "reg_or_0_operand" "rJ")) 585 (match_operand:SI 3 "const_int_operand")] ;; model 586 UNSPEC_SYNC_OLD_OP))] 587 "" 588{ 589 union loongarch_gen_fn_ptrs generator; 590 generator.fn_7 = gen_atomic_cas_value_or_7_si; 591 loongarch_expand_atomic_qihi (generator, operands[0], operands[1], 592 operands[1], operands[2], operands[3]); 593 DONE; 594}) 595 596(define_expand "atomic_fetch_nand<mode>" 597 [(set (match_operand:SHORT 0 "register_operand" "=&r") 598 (match_operand:SHORT 1 "memory_operand" "+ZB")) 599 (set (match_dup 1) 600 (unspec_volatile:SHORT 601 [(not:SHORT (and:SHORT (match_dup 1) 602 (match_operand:SHORT 2 "reg_or_0_operand" "rJ"))) 603 (match_operand:SI 3 "const_int_operand")] ;; model 604 UNSPEC_SYNC_OLD_OP))] 605 "" 606{ 607 union loongarch_gen_fn_ptrs generator; 608 generator.fn_7 = gen_atomic_cas_value_nand_7_si; 609 loongarch_expand_atomic_qihi (generator, operands[0], operands[1], 610 operands[1], operands[2], operands[3]); 611 DONE; 612}) 613