This PR shows that we get the load/store_lanes logic wrong for arm big-endian.
[official-gcc.git] / gcc / config / mips / sync.md
blob426fccca998e0fcfa962047cb5ca839b76167ca2
1 ;;  Machine Description for MIPS based processor synchronization
2 ;;  instructions.
3 ;;  Copyright (C) 2007-2018 Free Software Foundation, Inc.
5 ;; This file is part of GCC.
7 ;; GCC is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation; either version 3, or (at your option)
10 ;; any later version.
12 ;; GCC is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GCC; see the file COPYING3.  If not see
19 ;; <http://www.gnu.org/licenses/>.
21 (define_c_enum "unspec" [
22   UNSPEC_COMPARE_AND_SWAP
23   UNSPEC_COMPARE_AND_SWAP_12
24   UNSPEC_SYNC_OLD_OP
25   UNSPEC_SYNC_NEW_OP
26   UNSPEC_SYNC_NEW_OP_12
27   UNSPEC_SYNC_OLD_OP_12
28   UNSPEC_SYNC_EXCHANGE
29   UNSPEC_SYNC_EXCHANGE_12
30   UNSPEC_MEMORY_BARRIER
31   UNSPEC_ATOMIC_COMPARE_AND_SWAP
32   UNSPEC_ATOMIC_EXCHANGE
33   UNSPEC_ATOMIC_FETCH_OP
36 ;; Atomic fetch bitwise operations.
37 (define_code_iterator fetchop_bit [ior xor and])
39 ;; Atomic HI and QI operations
40 (define_code_iterator atomic_hiqi_op [plus minus ior xor and])
42 ;; Atomic memory operations.
44 (define_expand "memory_barrier"
45   [(set (match_dup 0)
46         (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))]
47   "GENERATE_SYNC"
49   operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
50   MEM_VOLATILE_P (operands[0]) = 1;
53 (define_insn "*memory_barrier"
54   [(set (match_operand:BLK 0 "" "")
55         (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))]
56   "GENERATE_SYNC"
57   { return mips_output_sync (); })
59 ;; Can be removed in favor of atomic_compare_and_swap below.
60 (define_insn "sync_compare_and_swap<mode>"
61   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
62         (match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
63    (set (match_dup 1)
64         (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "dJ,dJ")
65                               (match_operand:GPR 3 "arith_operand" "I,d")]
66          UNSPEC_COMPARE_AND_SWAP))]
67   "GENERATE_LL_SC"
68   { return mips_output_sync_loop (insn, operands); }
69   [(set_attr "sync_insn1" "li,move")
70    (set_attr "sync_oldval" "0")
71    (set_attr "sync_mem" "1")
72    (set_attr "sync_required_oldval" "2")
73    (set_attr "sync_insn1_op2" "3")])
75 (define_expand "sync_compare_and_swap<mode>"
76   [(match_operand:SHORT 0 "register_operand")
77    (match_operand:SHORT 1 "memory_operand")
78    (match_operand:SHORT 2 "general_operand")
79    (match_operand:SHORT 3 "general_operand")]
80   "GENERATE_LL_SC"
82   union mips_gen_fn_ptrs generator;
83   generator.fn_6 = gen_compare_and_swap_12;
84   mips_expand_atomic_qihi (generator,
85                            operands[0], operands[1], operands[2], operands[3]);
86   DONE;
89 ;; Helper insn for mips_expand_atomic_qihi.
90 (define_insn "compare_and_swap_12"
91   [(set (match_operand:SI 0 "register_operand" "=&d,&d")
92         (match_operand:SI 1 "memory_operand" "+ZC,ZC"))
93    (set (match_dup 1)
94         (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d")
95                              (match_operand:SI 3 "register_operand" "d,d")
96                              (match_operand:SI 4 "reg_or_0_operand" "dJ,dJ")
97                              (match_operand:SI 5 "reg_or_0_operand" "d,J")]
98                             UNSPEC_COMPARE_AND_SWAP_12))]
99   "GENERATE_LL_SC"
100   { return mips_output_sync_loop (insn, operands); }
101   [(set_attr "sync_oldval" "0")
102    (set_attr "sync_mem" "1")
103    (set_attr "sync_inclusive_mask" "2")
104    (set_attr "sync_exclusive_mask" "3")
105    (set_attr "sync_required_oldval" "4")
106    (set_attr "sync_insn1_op2" "5")])
108 (define_insn "sync_add<mode>"
109   [(set (match_operand:GPR 0 "memory_operand" "+ZC,ZC")
110         (unspec_volatile:GPR
111           [(plus:GPR (match_dup 0)
112                      (match_operand:GPR 1 "arith_operand" "I,d"))]
113           UNSPEC_SYNC_OLD_OP))]
114   "GENERATE_LL_SC"
115   { return mips_output_sync_loop (insn, operands); }
116   [(set_attr "sync_insn1" "addiu,addu")
117    (set_attr "sync_mem" "0")
118    (set_attr "sync_insn1_op2" "1")])
120 (define_expand "sync_<optab><mode>"
121   [(set (match_operand:SHORT 0 "memory_operand")
122         (unspec_volatile:SHORT
123           [(atomic_hiqi_op:SHORT (match_dup 0)
124                                  (match_operand:SHORT 1 "general_operand"))]
125           UNSPEC_SYNC_OLD_OP))]
126   "GENERATE_LL_SC"
128   union mips_gen_fn_ptrs generator;
129   generator.fn_4 = gen_sync_<optab>_12;
130   mips_expand_atomic_qihi (generator,
131                            NULL, operands[0], operands[1], NULL);
132   DONE;
135 ;; Helper insn for sync_<optab><mode>
136 (define_insn "sync_<optab>_12"
137   [(set (match_operand:SI 0 "memory_operand" "+ZC")
138         (unspec_volatile:SI
139           [(match_operand:SI 1 "register_operand" "d")
140            (match_operand:SI 2 "register_operand" "d")
141            (atomic_hiqi_op:SI (match_dup 0)
142                               (match_operand:SI 3 "reg_or_0_operand" "dJ"))]
143           UNSPEC_SYNC_OLD_OP_12))
144    (clobber (match_scratch:SI 4 "=&d"))]
145   "GENERATE_LL_SC"
146   { return mips_output_sync_loop (insn, operands); }
147   [(set_attr "sync_insn1" "<insn>")
148    (set_attr "sync_insn2" "and")
149    (set_attr "sync_mem" "0")
150    (set_attr "sync_inclusive_mask" "1")
151    (set_attr "sync_exclusive_mask" "2")
152    (set_attr "sync_insn1_op2" "3")
153    (set_attr "sync_oldval" "4")
154    (set_attr "sync_newval" "4")])
156 (define_expand "sync_old_<optab><mode>"
157   [(parallel [
158      (set (match_operand:SHORT 0 "register_operand")
159           (match_operand:SHORT 1 "memory_operand"))
160      (set (match_dup 1)
161           (unspec_volatile:SHORT [(atomic_hiqi_op:SHORT
162                                     (match_dup 1)
163                                     (match_operand:SHORT 2 "general_operand"))]
164             UNSPEC_SYNC_OLD_OP))])]
165   "GENERATE_LL_SC"
167   union mips_gen_fn_ptrs generator;
168   generator.fn_5 = gen_sync_old_<optab>_12;
169   mips_expand_atomic_qihi (generator,
170                            operands[0], operands[1], operands[2], NULL);
171   DONE;
174 ;; Helper insn for sync_old_<optab><mode>
175 (define_insn "sync_old_<optab>_12"
176   [(set (match_operand:SI 0 "register_operand" "=&d")
177         (match_operand:SI 1 "memory_operand" "+ZC"))
178    (set (match_dup 1)
179         (unspec_volatile:SI
180           [(match_operand:SI 2 "register_operand" "d")
181            (match_operand:SI 3 "register_operand" "d")
182            (atomic_hiqi_op:SI (match_dup 0)
183                               (match_operand:SI 4 "reg_or_0_operand" "dJ"))]
184           UNSPEC_SYNC_OLD_OP_12))
185    (clobber (match_scratch:SI 5 "=&d"))]
186   "GENERATE_LL_SC"
187   { return mips_output_sync_loop (insn, operands); }
188   [(set_attr "sync_insn1" "<insn>")
189    (set_attr "sync_insn2" "and")
190    (set_attr "sync_oldval" "0")
191    (set_attr "sync_mem" "1")
192    (set_attr "sync_inclusive_mask" "2")
193    (set_attr "sync_exclusive_mask" "3")
194    (set_attr "sync_insn1_op2" "4")
195    (set_attr "sync_newval" "5")])
197 (define_expand "sync_new_<optab><mode>"
198   [(parallel [
199      (set (match_operand:SHORT 0 "register_operand")
200           (unspec_volatile:SHORT [(atomic_hiqi_op:SHORT
201                                     (match_operand:SHORT 1 "memory_operand")
202                                     (match_operand:SHORT 2 "general_operand"))]
203             UNSPEC_SYNC_NEW_OP))
204      (set (match_dup 1)
205           (unspec_volatile:SHORT [(match_dup 1) (match_dup 2)]
206             UNSPEC_SYNC_NEW_OP))])]
207   "GENERATE_LL_SC"
209   union mips_gen_fn_ptrs generator;
210   generator.fn_5 = gen_sync_new_<optab>_12;
211   mips_expand_atomic_qihi (generator,
212                            operands[0], operands[1], operands[2], NULL);
213   DONE;
216 ;; Helper insn for sync_new_<optab><mode>
217 (define_insn "sync_new_<optab>_12"
218   [(set (match_operand:SI 0 "register_operand" "=&d")
219         (unspec_volatile:SI
220           [(match_operand:SI 1 "memory_operand" "+ZC")
221            (match_operand:SI 2 "register_operand" "d")
222            (match_operand:SI 3 "register_operand" "d")
223            (atomic_hiqi_op:SI (match_dup 0)
224                               (match_operand:SI 4 "reg_or_0_operand" "dJ"))]
225           UNSPEC_SYNC_NEW_OP_12))
226    (set (match_dup 1)
227         (unspec_volatile:SI
228           [(match_dup 1)
229            (match_dup 2)
230            (match_dup 3)
231            (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))]
232   "GENERATE_LL_SC"
233   { return mips_output_sync_loop (insn, operands); }
234   [(set_attr "sync_insn1" "<insn>")
235    (set_attr "sync_insn2" "and")
236    (set_attr "sync_oldval" "0")
237    (set_attr "sync_newval" "0")
238    (set_attr "sync_mem" "1")
239    (set_attr "sync_inclusive_mask" "2")
240    (set_attr "sync_exclusive_mask" "3")
241    (set_attr "sync_insn1_op2" "4")])
243 (define_expand "sync_nand<mode>"
244   [(set (match_operand:SHORT 0 "memory_operand")
245         (unspec_volatile:SHORT
246           [(match_dup 0)
247            (match_operand:SHORT 1 "general_operand")]
248           UNSPEC_SYNC_OLD_OP))]
249   "GENERATE_LL_SC"
251   union mips_gen_fn_ptrs generator;
252   generator.fn_4 = gen_sync_nand_12;
253   mips_expand_atomic_qihi (generator,
254                            NULL, operands[0], operands[1], NULL);
255   DONE;
258 ;; Helper insn for sync_nand<mode>
259 (define_insn "sync_nand_12"
260   [(set (match_operand:SI 0 "memory_operand" "+ZC")
261         (unspec_volatile:SI
262           [(match_operand:SI 1 "register_operand" "d")
263            (match_operand:SI 2 "register_operand" "d")
264            (match_dup 0)
265            (match_operand:SI 3 "reg_or_0_operand" "dJ")]
266           UNSPEC_SYNC_OLD_OP_12))
267    (clobber (match_scratch:SI 4 "=&d"))]
268   "GENERATE_LL_SC"
269   { return mips_output_sync_loop (insn, operands); }
270   [(set_attr "sync_insn1" "and")
271    (set_attr "sync_insn2" "xor")
272    (set_attr "sync_mem" "0")
273    (set_attr "sync_inclusive_mask" "1")
274    (set_attr "sync_exclusive_mask" "2")
275    (set_attr "sync_insn1_op2" "3")
276    (set_attr "sync_oldval" "4")
277    (set_attr "sync_newval" "4")])
279 (define_expand "sync_old_nand<mode>"
280   [(parallel [
281      (set (match_operand:SHORT 0 "register_operand")
282           (match_operand:SHORT 1 "memory_operand"))
283      (set (match_dup 1)
284           (unspec_volatile:SHORT [(match_dup 1)
285                                   (match_operand:SHORT 2 "general_operand")]
286             UNSPEC_SYNC_OLD_OP))])]
287   "GENERATE_LL_SC"
289   union mips_gen_fn_ptrs generator;
290   generator.fn_5 = gen_sync_old_nand_12;
291   mips_expand_atomic_qihi (generator,
292                            operands[0], operands[1], operands[2], NULL);
293   DONE;
296 ;; Helper insn for sync_old_nand<mode>
297 (define_insn "sync_old_nand_12"
298   [(set (match_operand:SI 0 "register_operand" "=&d")
299         (match_operand:SI 1 "memory_operand" "+ZC"))
300    (set (match_dup 1)
301         (unspec_volatile:SI
302           [(match_operand:SI 2 "register_operand" "d")
303            (match_operand:SI 3 "register_operand" "d")
304            (match_operand:SI 4 "reg_or_0_operand" "dJ")]
305           UNSPEC_SYNC_OLD_OP_12))
306    (clobber (match_scratch:SI 5 "=&d"))]
307   "GENERATE_LL_SC"
308   { return mips_output_sync_loop (insn, operands); }
309   [(set_attr "sync_insn1" "and")
310    (set_attr "sync_insn2" "xor")
311    (set_attr "sync_oldval" "0")
312    (set_attr "sync_mem" "1")
313    (set_attr "sync_inclusive_mask" "2")
314    (set_attr "sync_exclusive_mask" "3")
315    (set_attr "sync_insn1_op2" "4")
316    (set_attr "sync_newval" "5")])
318 (define_expand "sync_new_nand<mode>"
319   [(parallel [
320      (set (match_operand:SHORT 0 "register_operand")
321           (unspec_volatile:SHORT [(match_operand:SHORT 1 "memory_operand")
322                                   (match_operand:SHORT 2 "general_operand")]
323             UNSPEC_SYNC_NEW_OP))
324      (set (match_dup 1)
325           (unspec_volatile:SHORT [(match_dup 1) (match_dup 2)]
326             UNSPEC_SYNC_NEW_OP))])]
327   "GENERATE_LL_SC"
329   union mips_gen_fn_ptrs generator;
330   generator.fn_5 = gen_sync_new_nand_12;
331   mips_expand_atomic_qihi (generator,
332                            operands[0], operands[1], operands[2], NULL);
333   DONE;
336 ;; Helper insn for sync_new_nand<mode>
337 (define_insn "sync_new_nand_12"
338   [(set (match_operand:SI 0 "register_operand" "=&d")
339         (unspec_volatile:SI
340           [(match_operand:SI 1 "memory_operand" "+ZC")
341            (match_operand:SI 2 "register_operand" "d")
342            (match_operand:SI 3 "register_operand" "d")
343            (match_operand:SI 4 "reg_or_0_operand" "dJ")]
344           UNSPEC_SYNC_NEW_OP_12))
345    (set (match_dup 1)
346         (unspec_volatile:SI
347           [(match_dup 1)
348            (match_dup 2)
349            (match_dup 3)
350            (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))]
351   "GENERATE_LL_SC"
352   { return mips_output_sync_loop (insn, operands); }
353   [(set_attr "sync_insn1" "and")
354    (set_attr "sync_insn2" "xor")
355    (set_attr "sync_oldval" "0")
356    (set_attr "sync_newval" "0")
357    (set_attr "sync_mem" "1")
358    (set_attr "sync_inclusive_mask" "2")
359    (set_attr "sync_exclusive_mask" "3")
360    (set_attr "sync_insn1_op2" "4")])
362 (define_insn "sync_sub<mode>"
363   [(set (match_operand:GPR 0 "memory_operand" "+ZC")
364         (unspec_volatile:GPR
365           [(minus:GPR (match_dup 0)
366                       (match_operand:GPR 1 "register_operand" "d"))]
367          UNSPEC_SYNC_OLD_OP))]
368   "GENERATE_LL_SC"
369   { return mips_output_sync_loop (insn, operands); }
370   [(set_attr "sync_insn1" "subu")
371    (set_attr "sync_mem" "0")
372    (set_attr "sync_insn1_op2" "1")])
374 ;; Can be removed in favor of atomic_fetch_add below.
375 (define_insn "sync_old_add<mode>"
376   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
377         (match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
378    (set (match_dup 1)
379         (unspec_volatile:GPR
380           [(plus:GPR (match_dup 1)
381                      (match_operand:GPR 2 "arith_operand" "I,d"))]
382          UNSPEC_SYNC_OLD_OP))]
383   "GENERATE_LL_SC"
384   { return mips_output_sync_loop (insn, operands); }
385   [(set_attr "sync_insn1" "addiu,addu")
386    (set_attr "sync_oldval" "0")
387    (set_attr "sync_mem" "1")
388    (set_attr "sync_insn1_op2" "2")])
390 (define_insn "sync_old_sub<mode>"
391   [(set (match_operand:GPR 0 "register_operand" "=&d")
392         (match_operand:GPR 1 "memory_operand" "+ZC"))
393    (set (match_dup 1)
394         (unspec_volatile:GPR
395           [(minus:GPR (match_dup 1)
396                       (match_operand:GPR 2 "register_operand" "d"))]
397          UNSPEC_SYNC_OLD_OP))]
398   "GENERATE_LL_SC"
399   { return mips_output_sync_loop (insn, operands); }
400   [(set_attr "sync_insn1" "subu")
401    (set_attr "sync_oldval" "0")
402    (set_attr "sync_mem" "1")
403    (set_attr "sync_insn1_op2" "2")])
405 (define_insn "sync_new_add<mode>"
406   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
407         (plus:GPR (match_operand:GPR 1 "memory_operand" "+ZC,ZC")
408                   (match_operand:GPR 2 "arith_operand" "I,d")))
409    (set (match_dup 1)
410         (unspec_volatile:GPR
411           [(plus:GPR (match_dup 1) (match_dup 2))]
412          UNSPEC_SYNC_NEW_OP))]
413   "GENERATE_LL_SC"
414   { return mips_output_sync_loop (insn, operands); }
415   [(set_attr "sync_insn1" "addiu,addu")
416    (set_attr "sync_oldval" "0")
417    (set_attr "sync_newval" "0")
418    (set_attr "sync_mem" "1")
419    (set_attr "sync_insn1_op2" "2")])
421 (define_insn "sync_new_sub<mode>"
422   [(set (match_operand:GPR 0 "register_operand" "=&d")
423         (minus:GPR (match_operand:GPR 1 "memory_operand" "+ZC")
424                    (match_operand:GPR 2 "register_operand" "d")))
425    (set (match_dup 1)
426         (unspec_volatile:GPR
427           [(minus:GPR (match_dup 1) (match_dup 2))]
428          UNSPEC_SYNC_NEW_OP))]
429   "GENERATE_LL_SC"
430   { return mips_output_sync_loop (insn, operands); }
431   [(set_attr "sync_insn1" "subu")
432    (set_attr "sync_oldval" "0")
433    (set_attr "sync_newval" "0")
434    (set_attr "sync_mem" "1")
435    (set_attr "sync_insn1_op2" "2")])
437 (define_insn "sync_<optab><mode>"
438   [(set (match_operand:GPR 0 "memory_operand" "+ZC,ZC")
439         (unspec_volatile:GPR
440           [(fetchop_bit:GPR (match_operand:GPR 1 "uns_arith_operand" "K,d")
441                               (match_dup 0))]
442          UNSPEC_SYNC_OLD_OP))]
443   "GENERATE_LL_SC"
444   { return mips_output_sync_loop (insn, operands); }
445   [(set_attr "sync_insn1" "<immediate_insn>,<insn>")
446    (set_attr "sync_mem" "0")
447    (set_attr "sync_insn1_op2" "1")])
449 (define_insn "sync_old_<optab><mode>"
450   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
451         (match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
452    (set (match_dup 1)
453         (unspec_volatile:GPR
454           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
455                             (match_dup 1))]
456          UNSPEC_SYNC_OLD_OP))]
457   "GENERATE_LL_SC"
458   { return mips_output_sync_loop (insn, operands); }
459   [(set_attr "sync_insn1" "<immediate_insn>,<insn>")
460    (set_attr "sync_oldval" "0")
461    (set_attr "sync_mem" "1")
462    (set_attr "sync_insn1_op2" "2")])
464 (define_insn "sync_new_<optab><mode>"
465   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
466         (match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
467    (set (match_dup 1)
468         (unspec_volatile:GPR
469           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
470                             (match_dup 1))]
471          UNSPEC_SYNC_NEW_OP))]
472   "GENERATE_LL_SC"
473   { return mips_output_sync_loop (insn, operands); }
474   [(set_attr "sync_insn1" "<immediate_insn>,<insn>")
475    (set_attr "sync_oldval" "0")
476    (set_attr "sync_newval" "0")
477    (set_attr "sync_mem" "1")
478    (set_attr "sync_insn1_op2" "2")])
480 (define_insn "sync_nand<mode>"
481   [(set (match_operand:GPR 0 "memory_operand" "+ZC,ZC")
482         (unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")]
483          UNSPEC_SYNC_OLD_OP))]
484   "GENERATE_LL_SC"
485   { return mips_output_sync_loop (insn, operands); }
486   [(set_attr "sync_insn1" "andi,and")
487    (set_attr "sync_insn2" "not")
488    (set_attr "sync_mem" "0")
489    (set_attr "sync_insn1_op2" "1")])
491 (define_insn "sync_old_nand<mode>"
492   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
493         (match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
494    (set (match_dup 1)
495         (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
496          UNSPEC_SYNC_OLD_OP))]
497   "GENERATE_LL_SC"
498   { return mips_output_sync_loop (insn, operands); }
499   [(set_attr "sync_insn1" "andi,and")
500    (set_attr "sync_insn2" "not")
501    (set_attr "sync_oldval" "0")
502    (set_attr "sync_mem" "1")
503    (set_attr "sync_insn1_op2" "2")])
505 (define_insn "sync_new_nand<mode>"
506   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
507         (match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
508    (set (match_dup 1)
509         (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
510          UNSPEC_SYNC_NEW_OP))]
511   "GENERATE_LL_SC"
512   { return mips_output_sync_loop (insn, operands); }
513   [(set_attr "sync_insn1" "andi,and")
514    (set_attr "sync_insn2" "not")
515    (set_attr "sync_oldval" "0")
516    (set_attr "sync_newval" "0")
517    (set_attr "sync_mem" "1")
518    (set_attr "sync_insn1_op2" "2")])
520 (define_insn "sync_lock_test_and_set<mode>"
521   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
522         (match_operand:GPR 1 "memory_operand" "+ZC,ZC"))
523    (set (match_dup 1)
524         (unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
525          UNSPEC_SYNC_EXCHANGE))]
526   "GENERATE_LL_SC"
527   { return mips_output_sync_loop (insn, operands); }
528   [(set_attr "sync_memmodel" "11")
529    (set_attr "sync_insn1" "li,move")
530    (set_attr "sync_oldval" "0")
531    (set_attr "sync_mem" "1")
532    (set_attr "sync_insn1_op2" "2")])
534 (define_expand "sync_lock_test_and_set<mode>"
535   [(match_operand:SHORT 0 "register_operand")
536    (match_operand:SHORT 1 "memory_operand")
537    (match_operand:SHORT 2 "general_operand")]
538   "GENERATE_LL_SC"
540   union mips_gen_fn_ptrs generator;
541   generator.fn_5 = gen_test_and_set_12;
542   mips_expand_atomic_qihi (generator,
543                            operands[0], operands[1], operands[2], NULL);
544   DONE;
547 (define_insn "test_and_set_12"
548   [(set (match_operand:SI 0 "register_operand" "=&d")
549         (match_operand:SI 1 "memory_operand" "+ZC"))
550    (set (match_dup 1)
551         (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d")
552                              (match_operand:SI 3 "register_operand" "d")
553                              (match_operand:SI 4 "reg_or_0_operand" "dJ")]
554           UNSPEC_SYNC_EXCHANGE_12))]
555   "GENERATE_LL_SC"
556   { return mips_output_sync_loop (insn, operands); }
557   [(set_attr "sync_memmodel" "11")
558    (set_attr "sync_oldval" "0")
559    (set_attr "sync_mem" "1")
560    ;; Unused, but needed to give the number of operands expected by
561    ;; the expander.
562    (set_attr "sync_inclusive_mask" "2")
563    (set_attr "sync_exclusive_mask" "3")
564    (set_attr "sync_insn1_op2" "4")])
566 (define_insn "atomic_compare_and_swap<mode>"
567   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
568         ;; Logically this unspec is an "eq" operator, but we need to obscure
569         ;; reads and writes from/to memory with an unspec to prevent
570         ;; optimizations on shared memory locations.  Otherwise, comparison in
571         ;; { mem = 2; if (atomic_cmp_swap(mem,...) == 2) ...; }
572         ;; would be optimized away.  In addition to that we need to use
573         ;; unspec_volatile, not just plain unspec -- for the sake of other
574         ;; threads -- to make sure we don't remove the entirety of the pattern
575         ;; just because current thread doesn't observe any effect from it.
576         ;; TODO: the obscuring unspec can be relaxed for permissive memory
577         ;; models.
578         ;; Same applies to other atomic_* patterns.
579         (unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+ZC,ZC")
580                               (match_operand:GPR 3 "reg_or_0_operand" "dJ,dJ")]
581          UNSPEC_ATOMIC_COMPARE_AND_SWAP))
582    (set (match_operand:GPR 1 "register_operand" "=&d,&d")
583         (unspec_volatile:GPR [(match_dup 2)]
584          UNSPEC_ATOMIC_COMPARE_AND_SWAP))
585    (set (match_dup 2)
586         (unspec_volatile:GPR [(match_dup 2)
587                               (match_dup 3)
588                               (match_operand:GPR 4 "arith_operand" "I,d")]
589          UNSPEC_ATOMIC_COMPARE_AND_SWAP))
590    (unspec_volatile:GPR [(match_operand:SI 5 "const_int_operand")
591                          (match_operand:SI 6 "const_int_operand")
592                          (match_operand:SI 7 "const_int_operand")]
593     UNSPEC_ATOMIC_COMPARE_AND_SWAP)]
594   "GENERATE_LL_SC"
595   { return mips_output_sync_loop (insn, operands); }
596   [(set_attr "sync_insn1" "li,move")
597    (set_attr "sync_oldval" "1")
598    (set_attr "sync_cmp" "0")
599    (set_attr "sync_mem" "2")
600    (set_attr "sync_required_oldval" "3")
601    (set_attr "sync_insn1_op2" "4")
602    (set_attr "sync_memmodel" "6")])
604 (define_expand "atomic_exchange<mode>"
605   [(match_operand:GPR 0 "register_operand")
606    (match_operand:GPR 1 "memory_operand")
607    (match_operand:GPR 2 "arith_operand")
608    (match_operand:SI 3 "const_int_operand")]
609   "GENERATE_LL_SC || ISA_HAS_SWAP"
611   if (ISA_HAS_SWAP)
612     {
613       if (!mem_noofs_operand (operands[1], <MODE>mode))
614         {
615           rtx addr;
617           addr = force_reg (Pmode, XEXP (operands[1], 0));
618           operands[1] = replace_equiv_address (operands[1], addr);
619         }
620       operands[2] = force_reg (<MODE>mode, operands[2]);
621       emit_insn (gen_atomic_exchange<mode>_swap (operands[0], operands[1],
622                                                  operands[2]));
623     }
624   else
625     emit_insn (gen_atomic_exchange<mode>_llsc (operands[0], operands[1],
626                                                operands[2], operands[3]));
627   DONE;
630 (define_insn "atomic_exchange<mode>_llsc"
631   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
632         (unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZC,ZC")]
633          UNSPEC_ATOMIC_EXCHANGE))
634    (set (match_dup 1)
635         (unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
636          UNSPEC_ATOMIC_EXCHANGE))
637    (unspec_volatile:GPR [(match_operand:SI 3 "const_int_operand")]
638     UNSPEC_ATOMIC_EXCHANGE)]
639   "GENERATE_LL_SC && !ISA_HAS_SWAP"
640   { return mips_output_sync_loop (insn, operands); }
641   [(set_attr "sync_insn1" "li,move")
642    (set_attr "sync_oldval" "0")
643    (set_attr "sync_mem" "1")
644    (set_attr "sync_insn1_op2" "2")
645    (set_attr "sync_memmodel" "3")])
647 ;; XLP issues implicit sync for SWAP/LDADD, so no need for an explicit one.
648 (define_insn "atomic_exchange<mode>_swap"
649   [(set (match_operand:GPR 0 "register_operand" "=d")
650         (unspec_volatile:GPR [(match_operand:GPR 1 "mem_noofs_operand" "+ZR")]
651          UNSPEC_ATOMIC_EXCHANGE))
652    (set (match_dup 1)
653         (unspec_volatile:GPR [(match_operand:GPR 2 "register_operand" "0")]
654          UNSPEC_ATOMIC_EXCHANGE))]
655   "ISA_HAS_SWAP"
656   "swap<size>\t%0,%b1"
657   [(set_attr "type" "atomic")])
659 (define_expand "atomic_fetch_add<mode>"
660   [(match_operand:GPR 0 "register_operand")
661    (match_operand:GPR 1 "memory_operand")
662    (match_operand:GPR 2 "arith_operand")
663    (match_operand:SI 3 "const_int_operand")]
664   "GENERATE_LL_SC || ISA_HAS_LDADD"
666   if (ISA_HAS_LDADD)
667     {
668       if (!mem_noofs_operand (operands[1], <MODE>mode))
669         {
670           rtx addr;
672           addr = force_reg (Pmode, XEXP (operands[1], 0));
673           operands[1] = replace_equiv_address (operands[1], addr);
674         }
675       operands[2] = force_reg (<MODE>mode, operands[2]);
676       emit_insn (gen_atomic_fetch_add<mode>_ldadd (operands[0], operands[1],
677                                                    operands[2]));
678     }
679   else
680     emit_insn (gen_atomic_fetch_add<mode>_llsc (operands[0], operands[1],
681                                                 operands[2], operands[3]));
682   DONE;
685 (define_insn "atomic_fetch_add<mode>_llsc"
686   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
687         (unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZC,ZC")]
688          UNSPEC_ATOMIC_FETCH_OP))
689    (set (match_dup 1)
690         (unspec_volatile:GPR
691          [(plus:GPR (match_dup 1)
692                     (match_operand:GPR 2 "arith_operand" "I,d"))]
693          UNSPEC_ATOMIC_FETCH_OP))
694    (unspec_volatile:GPR [(match_operand:SI 3 "const_int_operand")]
695     UNSPEC_ATOMIC_FETCH_OP)]
696   "GENERATE_LL_SC && !ISA_HAS_LDADD"
697   { return mips_output_sync_loop (insn, operands); }
698   [(set_attr "sync_insn1" "addiu,addu")
699    (set_attr "sync_oldval" "0")
700    (set_attr "sync_mem" "1")
701    (set_attr "sync_insn1_op2" "2")
702    (set_attr "sync_memmodel" "3")])
704 ;; XLP issues implicit sync for SWAP/LDADD, so no need for an explicit one.
705 (define_insn "atomic_fetch_add<mode>_ldadd"
706   [(set (match_operand:GPR 0 "register_operand" "=d")
707         (unspec_volatile:GPR [(match_operand:GPR 1 "mem_noofs_operand" "+ZR")]
708          UNSPEC_ATOMIC_FETCH_OP))
709    (set (match_dup 1)
710         (unspec_volatile:GPR
711          [(plus:GPR (match_dup 1)
712                     (match_operand:GPR 2 "register_operand" "0"))]
713          UNSPEC_ATOMIC_FETCH_OP))]
714   "ISA_HAS_LDADD"
715   "ldadd<size>\t%0,%b1"
716   [(set_attr "type" "atomic")])