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