Home | History | Annotate | Line # | Download | only in loongarch
sync.md revision 1.1.1.1
      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