1;;  Machine Description for MIPS based processor synchronization
2;;  instructions.
3;;  Copyright (C) 2007-2015 Free Software Foundation, Inc.
4
5;; This file is part of GCC.
6
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.
11
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.
16
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/>.
20
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
34])
35
36;; Atomic fetch bitwise operations.
37(define_code_iterator fetchop_bit [ior xor and])
38
39;; Atomic HI and QI operations
40(define_code_iterator atomic_hiqi_op [plus minus ior xor and])
41
42;; Atomic memory operations.
43
44(define_expand "memory_barrier"
45  [(set (match_dup 0)
46	(unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))]
47  "GENERATE_SYNC"
48{
49  operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
50  MEM_VOLATILE_P (operands[0]) = 1;
51})
52
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 (); })
58
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")])
74
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"
81{
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;
87})
88
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")])
107
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")])
119
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"
127{
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;
133})
134
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")])
155
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"
166{
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;
172})
173
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")])
196
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"
208{
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;
214})
215
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")])
242
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"
250{
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;
256})
257
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")])
278
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"
288{
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;
294})
295
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")])
317
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"
328{
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;
334})
335
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")])
361
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")])
373
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")])
389
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")])
404
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")])
420
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")])
436
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")])
448
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")])
463
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")])
479
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")])
490
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")])
504
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")])
519
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")])
533
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"
539{
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;
545})
546
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")])
565
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")])
603
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"
610{
611  if (ISA_HAS_SWAP)
612    {
613      if (!mem_noofs_operand (operands[1], <MODE>mode))
614        {
615	  rtx addr;
616
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;
628})
629
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")])
646
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")])
658
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"
665{
666  if (ISA_HAS_LDADD)
667    {
668      if (!mem_noofs_operand (operands[1], <MODE>mode))
669        {
670	  rtx addr;
671
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;
683})
684
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")])
703
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")])
717