1;; Machine description for PowerPC synchronization instructions.
2;; Copyright (C) 2005 Free Software Foundation, Inc.
3;; Contributed by Geoffrey Keating.
4
5;; This file is part of GCC.
6
7;; GCC is free software; you can redistribute it and/or modify it
8;; under the terms of the GNU General Public License as published
9;; by the Free Software Foundation; either version 2, or (at your
10;; option) any later version.
11
12;; GCC is distributed in the hope that it will be useful, but WITHOUT
13;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15;; 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 COPYING.  If not, write to the
19;; Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
20;; MA 02110-1301, USA.
21
22(define_mode_attr larx [(SI "lwarx") (DI "ldarx")])
23(define_mode_attr stcx [(SI "stwcx.") (DI "stdcx.")])
24
25(define_code_macro FETCHOP [plus minus ior xor and])
26(define_code_attr fetchop_name
27  [(plus "add") (minus "sub") (ior "ior") (xor "xor") (and "and")])
28(define_code_attr fetchop_pred
29  [(plus "add_operand") (minus "gpc_reg_operand")
30   (ior "logical_operand") (xor "logical_operand") (and "and_operand")])
31(define_code_attr fetchopsi_constr
32  [(plus "rIL") (minus "r") (ior "rKL") (xor "rKL") (and "rTKL")])
33(define_code_attr fetchopdi_constr
34  [(plus "rIL") (minus "r") (ior "rKJF") (xor "rKJF") (and "rSTKJ")])
35
36(define_expand "memory_barrier"
37  [(set (mem:BLK (match_dup 0))
38	(unspec:BLK [(mem:BLK (match_dup 0))] UNSPEC_SYNC))]
39  ""
40{
41  operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
42  MEM_VOLATILE_P (operands[0]) = 1;
43})
44
45(define_insn "*sync_internal"
46  [(set (match_operand:BLK 0 "" "")
47	(unspec:BLK [(match_operand:BLK 1 "" "")] UNSPEC_SYNC))]
48  ""
49  "{dcs|sync}"
50  [(set_attr "type" "sync")])
51
52(define_insn "load_locked_<mode>"
53  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
54	(unspec_volatile:GPR
55	  [(match_operand:GPR 1 "memory_operand" "Z")] UNSPECV_LL))]
56  "TARGET_POWERPC"
57  "<larx> %0,%y1"
58  [(set_attr "type" "load_l")])
59
60(define_insn "store_conditional_<mode>"
61  [(set (match_operand:CC 0 "cc_reg_operand" "=x")
62	(unspec_volatile:CC [(const_int 0)] UNSPECV_SC))
63   (set (match_operand:GPR 1 "memory_operand" "=Z")
64	(match_operand:GPR 2 "gpc_reg_operand" "r"))]
65  "TARGET_POWERPC"
66  "<stcx> %2,%y1"
67  [(set_attr "type" "store_c")])
68
69(define_insn_and_split "sync_compare_and_swap<mode>"
70  [(set (match_operand:GPR 0 "gpc_reg_operand" "=&r")
71	(match_operand:GPR 1 "memory_operand" "+Z"))
72   (set (match_dup 1)
73	(unspec:GPR
74	  [(match_operand:GPR 2 "reg_or_short_operand" "rI")
75	   (match_operand:GPR 3 "gpc_reg_operand" "r")]
76	  UNSPEC_CMPXCHG))
77   (clobber (match_scratch:GPR 4 "=&r"))
78   (clobber (match_scratch:CC 5 "=&x"))]
79  "TARGET_POWERPC"
80  "#"
81  "&& reload_completed"
82  [(const_int 0)]
83{
84  rs6000_split_compare_and_swap (operands[0], operands[1], operands[2],
85				 operands[3], operands[4]);
86  DONE;
87})
88
89(define_expand "sync_compare_and_swaphi"
90  [(match_operand:HI 0 "gpc_reg_operand" "")
91   (match_operand:HI 1 "memory_operand" "")
92   (match_operand:HI 2 "gpc_reg_operand" "")
93   (match_operand:HI 3 "gpc_reg_operand" "")]
94  "TARGET_POWERPC"
95{
96  rs6000_expand_compare_and_swapqhi (operands[0], operands[1],
97				     operands[2], operands[3]);
98  DONE;
99})
100
101(define_expand "sync_compare_and_swapqi"
102  [(match_operand:QI 0 "gpc_reg_operand" "")
103   (match_operand:QI 1 "memory_operand" "")
104   (match_operand:QI 2 "gpc_reg_operand" "")
105   (match_operand:QI 3 "gpc_reg_operand" "")]
106  "TARGET_POWERPC"
107{
108  rs6000_expand_compare_and_swapqhi (operands[0], operands[1],
109				     operands[2], operands[3]);
110  DONE;
111})
112
113(define_insn_and_split "sync_compare_and_swapqhi_internal"
114  [(set (match_operand:SI 0 "gpc_reg_operand" "=&r")
115	(match_operand:SI 4 "memory_operand" "+Z"))
116   (set (match_dup 4)
117        (unspec:SI
118          [(match_operand:SI 1 "gpc_reg_operand" "r")
119           (match_operand:SI 2 "gpc_reg_operand" "r")
120           (match_operand:SI 3 "gpc_reg_operand" "r")]
121          UNSPEC_CMPXCHG))
122   (clobber (match_scratch:SI 5 "=&r"))
123   (clobber (match_scratch:CC 6 "=&x"))]
124  "TARGET_POWERPC"
125  "#"
126  "&& reload_completed"
127  [(const_int 0)]
128{
129  rs6000_split_compare_and_swapqhi (operands[0], operands[1],
130				    operands[2], operands[3], operands[4],
131				    operands[5]);
132  DONE;
133})
134
135(define_insn_and_split "sync_lock_test_and_set<mode>"
136  [(set (match_operand:GPR 0 "gpc_reg_operand" "=&r")
137	(match_operand:GPR 1 "memory_operand" "+Z"))
138   (set (match_dup 1)
139	(unspec:GPR
140	  [(match_operand:GPR 2 "reg_or_short_operand" "rL")]
141	  UNSPEC_XCHG))
142   (clobber (match_scratch:GPR 3 "=&r"))
143   (clobber (match_scratch:CC 4 "=&x"))]
144  "TARGET_POWERPC"
145  "#"
146  "&& reload_completed"
147  [(const_int 0)]
148{
149  rs6000_split_lock_test_and_set (operands[0], operands[1], operands[2],
150				  operands[3]);
151  DONE;
152})
153
154(define_expand "sync_<fetchop_name><mode>"
155  [(parallel [(set (match_operand:INT1 0 "memory_operand" "")
156		   (unspec:INT1
157		     [(FETCHOP:INT1 (match_dup 0)
158			(match_operand:INT1 1 "<fetchop_pred>" ""))]
159		     UNSPEC_ATOMIC))
160	      (clobber (scratch:INT1))
161	      (clobber (scratch:CC))])]
162  "TARGET_POWERPC"
163  "
164{
165  if (<MODE>mode != SImode && <MODE>mode != DImode)
166    {
167      if (PPC405_ERRATUM77)
168	FAIL;
169      rs6000_emit_sync (<CODE>, <MODE>mode, operands[0], operands[1],
170			NULL_RTX, NULL_RTX, true);
171      DONE;
172    }
173}")
174
175(define_insn_and_split "*sync_<fetchop_name>si_internal"
176  [(set (match_operand:SI 0 "memory_operand" "+Z")
177	(unspec:SI
178	  [(FETCHOP:SI (match_dup 0)
179	     (match_operand:SI 1 "<fetchop_pred>" "<fetchopsi_constr>"))]
180	  UNSPEC_ATOMIC))
181   (clobber (match_scratch:SI 2 "=&b"))
182   (clobber (match_scratch:CC 3 "=&x"))]
183  "TARGET_POWERPC"
184  "#"
185  "&& reload_completed"
186  [(const_int 0)]
187{
188  rs6000_split_atomic_op (<CODE>, operands[0], operands[1],
189			  NULL_RTX, NULL_RTX, operands[2]);
190  DONE;
191})
192
193(define_insn_and_split "*sync_<fetchop_name>di_internal"
194  [(set (match_operand:DI 0 "memory_operand" "+Z")
195	(unspec:DI
196	  [(FETCHOP:DI (match_dup 0)
197	     (match_operand:DI 1 "<fetchop_pred>" "<fetchopdi_constr>"))]
198	  UNSPEC_ATOMIC))
199   (clobber (match_scratch:DI 2 "=&b"))
200   (clobber (match_scratch:CC 3 "=&x"))]
201  "TARGET_POWERPC"
202  "#"
203  "&& reload_completed"
204  [(const_int 0)]
205{
206  rs6000_split_atomic_op (<CODE>, operands[0], operands[1],
207			  NULL_RTX, NULL_RTX, operands[2]);
208  DONE;
209})
210
211(define_expand "sync_nand<mode>"
212  [(parallel [(set (match_operand:INT1 0 "memory_operand" "")
213	      (unspec:INT1
214		[(and:INT1 (not:INT1 (match_dup 0))
215		   (match_operand:INT1 1 "gpc_reg_operand" ""))]
216		UNSPEC_ATOMIC))
217	      (clobber (scratch:INT1))
218	      (clobber (scratch:CC))])]
219  "TARGET_POWERPC"
220  "
221{
222  if (<MODE>mode != SImode && <MODE>mode != DImode)
223    {
224      if (PPC405_ERRATUM77)
225	FAIL;
226      rs6000_emit_sync (AND, <MODE>mode,
227			gen_rtx_NOT (<MODE>mode, operands[0]),
228			operands[1],
229			NULL_RTX, NULL_RTX, true);
230      DONE;
231    }
232}")
233
234(define_insn_and_split "*sync_nand<mode>_internal"
235  [(set (match_operand:GPR 0 "memory_operand" "+Z")
236	(unspec:GPR
237	  [(and:GPR (not:GPR (match_dup 0))
238	     (match_operand:GPR 1 "gpc_reg_operand" "r"))]
239	  UNSPEC_ATOMIC))
240   (clobber (match_scratch:GPR 2 "=&r"))
241   (clobber (match_scratch:CC 3 "=&x"))]
242  "TARGET_POWERPC"
243  "#"
244  "&& reload_completed"
245  [(const_int 0)]
246{
247  rs6000_split_atomic_op (NOT, operands[0], operands[1],
248			  NULL_RTX, NULL_RTX, operands[2]);
249  DONE;
250})
251
252(define_expand "sync_old_<fetchop_name><mode>"
253  [(parallel [(set (match_operand:INT1 0 "gpc_reg_operand" "")
254		   (match_operand:INT1 1 "memory_operand" ""))
255	      (set (match_dup 1)
256		   (unspec:INT1
257		     [(FETCHOP:INT1 (match_dup 1)
258			(match_operand:INT1 2 "<fetchop_pred>" ""))]
259		     UNSPEC_ATOMIC))
260	      (clobber (scratch:INT1))
261	      (clobber (scratch:CC))])]
262  "TARGET_POWERPC"
263  "
264{ 
265  if (<MODE>mode != SImode && <MODE>mode != DImode)
266    {
267      if (PPC405_ERRATUM77)
268	FAIL;
269      rs6000_emit_sync (<CODE>, <MODE>mode, operands[1], operands[2],
270			operands[0], NULL_RTX, true);
271      DONE;
272    }
273}")
274
275(define_insn_and_split "*sync_old_<fetchop_name>si_internal"
276  [(set (match_operand:SI 0 "gpc_reg_operand" "=&r")
277	(match_operand:SI 1 "memory_operand" "+Z"))
278   (set (match_dup 1)
279	(unspec:SI
280	  [(FETCHOP:SI (match_dup 1)
281	     (match_operand:SI 2 "<fetchop_pred>" "<fetchopsi_constr>"))]
282	  UNSPEC_ATOMIC))
283   (clobber (match_scratch:SI 3 "=&b"))
284   (clobber (match_scratch:CC 4 "=&x"))]
285  "TARGET_POWERPC"
286  "#"
287  "&& reload_completed"
288  [(const_int 0)]
289{
290  rs6000_split_atomic_op (<CODE>, operands[1], operands[2],
291			  operands[0], NULL_RTX, operands[3]);
292  DONE;
293})
294
295(define_insn_and_split "*sync_old_<fetchop_name>di_internal"
296  [(set (match_operand:DI 0 "gpc_reg_operand" "=&r")
297	(match_operand:DI 1 "memory_operand" "+Z"))
298   (set (match_dup 1)
299	(unspec:DI
300	  [(FETCHOP:DI (match_dup 1)
301	     (match_operand:DI 2 "<fetchop_pred>" "<fetchopdi_constr>"))]
302	  UNSPEC_ATOMIC))
303   (clobber (match_scratch:DI 3 "=&b"))
304   (clobber (match_scratch:CC 4 "=&x"))]
305  "TARGET_POWERPC"
306  "#"
307  "&& reload_completed"
308  [(const_int 0)]
309{
310  rs6000_split_atomic_op (<CODE>, operands[1], operands[2],
311			  operands[0], NULL_RTX, operands[3]);
312  DONE;
313})
314
315(define_expand "sync_old_nand<mode>"
316  [(parallel [(set (match_operand:INT1 0 "gpc_reg_operand" "")
317		   (match_operand:INT1 1 "memory_operand" ""))
318	      (set (match_dup 1)
319		   (unspec:INT1
320		     [(and:INT1 (not:INT1 (match_dup 1))
321			(match_operand:INT1 2 "gpc_reg_operand" ""))]
322		     UNSPEC_ATOMIC))
323	      (clobber (scratch:INT1))
324	      (clobber (scratch:CC))])]
325  "TARGET_POWERPC"
326  "
327{
328  if (<MODE>mode != SImode && <MODE>mode != DImode)
329    {
330      if (PPC405_ERRATUM77)
331	FAIL;
332      rs6000_emit_sync (AND, <MODE>mode,
333			gen_rtx_NOT (<MODE>mode, operands[1]),
334			operands[2],
335			operands[0], NULL_RTX, true);
336      DONE;
337    }
338}")
339
340(define_insn_and_split "*sync_old_nand<mode>_internal"
341  [(set (match_operand:GPR 0 "gpc_reg_operand" "=&r")
342	(match_operand:GPR 1 "memory_operand" "+Z"))
343   (set (match_dup 1)
344	(unspec:GPR
345	  [(and:GPR (not:GPR (match_dup 1))
346	     (match_operand:GPR 2 "gpc_reg_operand" "r"))]
347	  UNSPEC_ATOMIC))
348   (clobber (match_scratch:GPR 3 "=&r"))
349   (clobber (match_scratch:CC 4 "=&x"))]
350  "TARGET_POWERPC"
351  "#"
352  "&& reload_completed"
353  [(const_int 0)]
354{
355  rs6000_split_atomic_op (NOT, operands[1], operands[2],
356			  operands[0], NULL_RTX, operands[3]);
357  DONE;
358})
359
360(define_expand "sync_new_<fetchop_name><mode>"
361  [(parallel [(set (match_operand:INT1 0 "gpc_reg_operand" "")
362		   (FETCHOP:INT1
363		     (match_operand:INT1 1 "memory_operand" "")
364		     (match_operand:INT1 2 "<fetchop_pred>" "")))
365	      (set (match_dup 1)
366		   (unspec:INT1
367		     [(FETCHOP:INT1 (match_dup 1) (match_dup 2))]
368		     UNSPEC_ATOMIC))
369	      (clobber (scratch:INT1))
370	      (clobber (scratch:CC))])]
371  "TARGET_POWERPC"
372  "
373{
374  if (<MODE>mode != SImode && <MODE>mode != DImode)
375    {
376      if (PPC405_ERRATUM77)
377	FAIL;
378      rs6000_emit_sync (<CODE>, <MODE>mode, operands[1], operands[2],
379			NULL_RTX, operands[0], true);
380      DONE;
381    }
382}")
383
384(define_insn_and_split "*sync_new_<fetchop_name>si_internal"
385  [(set (match_operand:SI 0 "gpc_reg_operand" "=&r")
386	(FETCHOP:SI
387	  (match_operand:SI 1 "memory_operand" "+Z")
388	  (match_operand:SI 2 "<fetchop_pred>" "<fetchopsi_constr>")))
389   (set (match_dup 1)
390	(unspec:SI
391	  [(FETCHOP:SI (match_dup 1) (match_dup 2))]
392	  UNSPEC_ATOMIC))
393   (clobber (match_scratch:SI 3 "=&b"))
394   (clobber (match_scratch:CC 4 "=&x"))]
395  "TARGET_POWERPC"
396  "#"
397  "&& reload_completed"
398  [(const_int 0)]
399{
400  rs6000_split_atomic_op (<CODE>, operands[1], operands[2],
401			  NULL_RTX, operands[0], operands[3]);
402  DONE;
403})
404
405(define_insn_and_split "*sync_new_<fetchop_name>di_internal"
406  [(set (match_operand:DI 0 "gpc_reg_operand" "=&r")
407	(FETCHOP:DI
408	  (match_operand:DI 1 "memory_operand" "+Z")
409	  (match_operand:DI 2 "<fetchop_pred>" "<fetchopdi_constr>")))
410   (set (match_dup 1)
411	(unspec:DI
412	  [(FETCHOP:DI (match_dup 1) (match_dup 2))]
413	  UNSPEC_ATOMIC))
414   (clobber (match_scratch:DI 3 "=&b"))
415   (clobber (match_scratch:CC 4 "=&x"))]
416  "TARGET_POWERPC"
417  "#"
418  "&& reload_completed"
419  [(const_int 0)]
420{
421  rs6000_split_atomic_op (<CODE>, operands[1], operands[2],
422			  NULL_RTX, operands[0], operands[3]);
423  DONE;
424})
425
426(define_expand "sync_new_nand<mode>"
427  [(parallel [(set (match_operand:INT1 0 "gpc_reg_operand" "")
428		   (and:INT1
429		     (not:INT1 (match_operand:INT1 1 "memory_operand" ""))
430		     (match_operand:INT1 2 "gpc_reg_operand" "")))
431	      (set (match_dup 1)
432		   (unspec:INT1
433		     [(and:INT1 (not:INT1 (match_dup 1)) (match_dup 2))]
434		     UNSPEC_ATOMIC))
435	      (clobber (scratch:INT1))
436	      (clobber (scratch:CC))])]
437  "TARGET_POWERPC"
438  "
439{
440  if (<MODE>mode != SImode && <MODE>mode != DImode)
441    {
442      if (PPC405_ERRATUM77)
443	FAIL;
444      rs6000_emit_sync (AND, <MODE>mode,
445			gen_rtx_NOT (<MODE>mode, operands[1]),
446			operands[2],
447			NULL_RTX, operands[0], true);
448      DONE;
449    }
450}")
451
452(define_insn_and_split "*sync_new_nand<mode>_internal"
453  [(set (match_operand:GPR 0 "gpc_reg_operand" "=&r")
454	(and:GPR
455	  (not:GPR (match_operand:GPR 1 "memory_operand" "+Z"))
456	  (match_operand:GPR 2 "gpc_reg_operand" "r")))
457   (set (match_dup 1)
458	(unspec:GPR
459	  [(and:GPR (not:GPR (match_dup 1)) (match_dup 2))]
460	  UNSPEC_ATOMIC))
461   (clobber (match_scratch:GPR 3 "=&r"))
462   (clobber (match_scratch:CC 4 "=&x"))]
463  "TARGET_POWERPC"
464  "#"
465  "&& reload_completed"
466  [(const_int 0)]
467{
468  rs6000_split_atomic_op (NOT, operands[1], operands[2],
469			  NULL_RTX, operands[0], operands[3]);
470  DONE;
471})
472
473; and<mode> without cr0 clobber to avoid generation of additional clobber 
474; in atomic splitters causing internal consistency failure.
475; cr0 already clobbered by larx/stcx.
476(define_insn "*atomic_andsi"
477  [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
478	(unspec:SI [(match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r")
479		    (match_operand:SI 2 "and_operand" "?r,T,K,L")]
480		    UNSPEC_AND))]
481  ""
482  "@
483   and %0,%1,%2
484   {rlinm|rlwinm} %0,%1,0,%m2,%M2
485   {andil.|andi.} %0,%1,%b2
486   {andiu.|andis.} %0,%1,%u2"
487  [(set_attr "type" "*,*,compare,compare")])
488
489(define_insn "*atomic_anddi"
490  [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,r")
491	(unspec:DI [(match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r")
492		    (match_operand:DI 2 "and_operand" "?r,S,T,K,J")]
493		    UNSPEC_AND))]
494  "TARGET_POWERPC64"
495  "@
496   and %0,%1,%2
497   rldic%B2 %0,%1,0,%S2
498   rlwinm %0,%1,0,%m2,%M2
499   andi. %0,%1,%b2
500   andis. %0,%1,%u2"
501  [(set_attr "type" "*,*,*,compare,compare")
502   (set_attr "length" "4,4,4,4,4")])
503
504; the sync_*_internal patterns all have these operands:
505; 0 - memory location
506; 1 - operand
507; 2 - value in memory after operation
508; 3 - value in memory immediately before operation
509
510(define_insn "*sync_addshort_internal"
511  [(set (match_operand:SI 2 "gpc_reg_operand" "=&r")
512	(ior:SI (and:SI (plus:SI (match_operand:SI 0 "memory_operand" "+Z")
513				 (match_operand:SI 1 "add_operand" "rI"))
514			(match_operand:SI 4 "gpc_reg_operand" "r"))
515		(and:SI (not:SI (match_dup 4)) (match_dup 0))))
516   (set (match_operand:SI 3 "gpc_reg_operand" "=&b") (match_dup 0))
517   (set (match_dup 0)
518	(unspec:SI [(ior:SI (and:SI (plus:SI (match_dup 0) (match_dup 1))
519				    (match_dup 4))
520			    (and:SI (not:SI (match_dup 4)) (match_dup 0)))]
521		   UNSPEC_SYNC_OP))
522   (clobber (match_scratch:CC 5 "=&x"))
523   (clobber (match_scratch:SI 6 "=&r"))]
524  "TARGET_POWERPC && !PPC405_ERRATUM77"
525  "lwarx %3,%y0\n\tadd%I1 %2,%3,%1\n\tandc %6,%3,%4\n\tand %2,%2,%4\n\tor %2,%2,%6\n\tstwcx. %2,%y0\n\tbne- $-24"
526  [(set_attr "length" "28")])
527
528(define_insn "*sync_subshort_internal"
529  [(set (match_operand:SI 2 "gpc_reg_operand" "=&r")
530	(ior:SI (and:SI (minus:SI (match_operand:SI 0 "memory_operand" "+Z")
531				  (match_operand:SI 1 "add_operand" "rI"))
532			(match_operand:SI 4 "gpc_reg_operand" "r"))
533		(and:SI (not:SI (match_dup 4)) (match_dup 0))))
534   (set (match_operand:SI 3 "gpc_reg_operand" "=&b") (match_dup 0))
535   (set (match_dup 0)
536	(unspec:SI [(ior:SI (and:SI (minus:SI (match_dup 0) (match_dup 1))
537				    (match_dup 4))
538			    (and:SI (not:SI (match_dup 4)) (match_dup 0)))]
539		   UNSPEC_SYNC_OP))
540   (clobber (match_scratch:CC 5 "=&x"))
541   (clobber (match_scratch:SI 6 "=&r"))]
542  "TARGET_POWERPC && !PPC405_ERRATUM77"
543  "lwarx %3,%y0\n\tsubf %2,%1,%3\n\tandc %6,%3,%4\n\tand %2,%2,%4\n\tor %2,%2,%6\n\tstwcx. %2,%y0\n\tbne- $-24"
544  [(set_attr "length" "28")])
545
546(define_insn "*sync_andsi_internal"
547  [(set (match_operand:SI 2 "gpc_reg_operand" "=&r,&r,&r,&r")
548	(and:SI (match_operand:SI 0 "memory_operand" "+Z,Z,Z,Z")
549		(match_operand:SI 1 "and_operand" "r,T,K,L")))
550   (set (match_operand:SI 3 "gpc_reg_operand" "=&b,&b,&b,&b") (match_dup 0))
551   (set (match_dup 0)
552	(unspec:SI [(and:SI (match_dup 0) (match_dup 1))]
553		   UNSPEC_SYNC_OP))
554   (clobber (match_scratch:CC 4 "=&x,&x,&x,&x"))]
555  "TARGET_POWERPC && !PPC405_ERRATUM77"
556  "@
557   lwarx %3,%y0\n\tand %2,%3,%1\n\tstwcx. %2,%y0\n\tbne- $-12
558   lwarx %3,%y0\n\trlwinm %2,%3,0,%m1,%M1\n\tstwcx. %2,%y0\n\tbne- $-12
559   lwarx %3,%y0\n\tandi. %2,%3,%b1\n\tstwcx. %2,%y0\n\tbne- $-12
560   lwarx %3,%y0\n\tandis. %2,%3,%u1\n\tstwcx. %2,%y0\n\tbne- $-12"
561  [(set_attr "length" "16,16,16,16")])
562
563(define_insn "*sync_boolsi_internal"
564  [(set (match_operand:SI 2 "gpc_reg_operand" "=&r,&r,&r")
565	(match_operator:SI 4 "boolean_or_operator"
566	 [(match_operand:SI 0 "memory_operand" "+Z,Z,Z")
567	  (match_operand:SI 1 "logical_operand" "r,K,L")]))
568   (set (match_operand:SI 3 "gpc_reg_operand" "=&b,&b,&b") (match_dup 0))
569   (set (match_dup 0) (unspec:SI [(match_dup 4)] UNSPEC_SYNC_OP))
570   (clobber (match_scratch:CC 5 "=&x,&x,&x"))]
571  "TARGET_POWERPC && !PPC405_ERRATUM77"
572  "@
573   lwarx %3,%y0\n\t%q4 %2,%3,%1\n\tstwcx. %2,%y0\n\tbne- $-12
574   lwarx %3,%y0\n\t%q4i %2,%3,%b1\n\tstwcx. %2,%y0\n\tbne- $-12
575   lwarx %3,%y0\n\t%q4is %2,%3,%u1\n\tstwcx. %2,%y0\n\tbne- $-12"
576  [(set_attr "length" "16,16,16")])
577
578; This pattern could also take immediate values of operand 1,
579; since the non-NOT version of the operator is used; but this is not
580; very useful, since in practice operand 1 is a full 32-bit value.
581; Likewise, operand 5 is in practice either <= 2^16 or it is a register.
582(define_insn "*sync_boolcshort_internal"
583  [(set (match_operand:SI 2 "gpc_reg_operand" "=&r")
584	(match_operator:SI 4 "boolean_operator"
585	 [(xor:SI (match_operand:SI 0 "memory_operand" "+Z")
586		  (match_operand:SI 5 "logical_operand" "rK"))
587	  (match_operand:SI 1 "gpc_reg_operand" "r")]))
588   (set (match_operand:SI 3 "gpc_reg_operand" "=&b") (match_dup 0))
589   (set (match_dup 0) (unspec:SI [(match_dup 4)] UNSPEC_SYNC_OP))
590   (clobber (match_scratch:CC 6 "=&x"))]
591  "TARGET_POWERPC && !PPC405_ERRATUM77"
592  "lwarx %3,%y0\n\txor%I2 %2,%3,%5\n\t%q4 %2,%2,%1\n\tstwcx. %2,%y0\n\tbne- $-16"
593  [(set_attr "length" "20")])
594
595(define_insn "isync"
596  [(set (mem:BLK (match_scratch 0 "X"))
597	(unspec_volatile:BLK [(mem:BLK (match_scratch 1 "X"))] UNSPEC_ISYNC))]
598  ""
599  "{ics|isync}"
600  [(set_attr "type" "isync")])
601
602(define_expand "sync_lock_release<mode>"
603  [(set (match_operand:INT 0 "memory_operand")
604	(match_operand:INT 1 "any_operand"))]
605  ""
606  "
607{
608  emit_insn (gen_lwsync ());
609  emit_move_insn (operands[0], operands[1]);
610  DONE;
611}")
612
613; Some AIX assemblers don't accept lwsync, so we use a .long.
614(define_insn "lwsync"
615  [(set (mem:BLK (match_scratch 0 "X"))
616	(unspec_volatile:BLK [(mem:BLK (match_scratch 1 "X"))] UNSPEC_LWSYNC))]
617  ""
618{
619  if (TARGET_NO_LWSYNC)
620    return "sync";
621  else
622    return ".long 0x7c2004ac";
623}
624  [(set_attr "type" "sync")])
625
626