1;; GCC machine description for SH synchronization instructions.
2;; Copyright (C) 2011-2019 Free Software Foundation, Inc.
3;;
4;; This file is part of GCC.
5;;
6;; GCC is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 3, or (at your option)
9;; any later version.
10;;
11;; GCC is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14;; GNU General Public License for more details.
15;;
16;; You should have received a copy of the GNU General Public License
17;; along with GCC; see the file COPYING3.  If not see
18;; <http://www.gnu.org/licenses/>.
19;;
20;;
21;; Atomic integer operations for the Renesas / SuperH SH CPUs.
22;;
23;; On SH CPUs atomic integer operations can be done either in 'software' or
24;; in 'hardware' in various styles.  True hardware support was introduced
25;; with the SH4A.  Some SH2A dual-core models (e.g. SH7205) also come with
26;; 'semaphore' hardware registers, but these are currently unsupported.
27;; All SH CPUs support the 'tas.b' instruction, which can be optionally used
28;; to implement the 'atomic_test_and_set' builtin.
29;; The following atomic options and models are supported.
30;;
31;; tas.b atomic_test_and_set (-mtas)
32;;
33;; Depending on the particular hardware configuration, usage of the 'tas.b'
34;; instruction might be undesired or even unsafe.  Thus, it has to be
35;; enabled by the user explicitly.  If it is not enabled, the
36;; 'atomic_test_and_set' builtin is implemented either with hardware or with
37;; software atomics, depending on which is enabled.  It is also possible to
38;; enable the 'tas.b' instruction only, without enabling support for the
39;; other atomic operations.
40;;
41;;
42;; Hardware Atomics (-matomic-model=hard-llcs; SH4A only)
43;;
44;; Hardware atomics implement all atomic operations using the 'movli.l' and
45;; 'movco.l' instructions that are availble on SH4A.  On multi-core hardware
46;; configurations hardware atomics is the only safe mode.
47;; However, it can also be safely used on single-core configurations.
48;; Since these instructions operate on SImode memory only, QImode and HImode
49;; have to be emulated with SImode and subreg masking, which results in
50;; larger code.
51;;
52;;
53;; gUSA Software Atomics (-matomic-model=soft-gusa; SH3*, SH4* only)
54;;
55;; On single-core systems there can only be one execution context running
56;; at a given point in time.  This allows the usage of rewindable atomic
57;; sequences, which effectively emulate locked-load / conditional-store
58;; operations.  This requires complementary support in the interrupt /
59;; exception handling code (e.g. kernel) and does not work safely on multi-
60;; core configurations.
61;;
62;; When an execution context is interrupted while it is an atomic
63;; sequence, the interrupted context's PC is rewound to the beginning of
64;; the atomic sequence by the interrupt / exception handling code, before
65;; transferring control to another execution context.  This is done by
66;; something like...
67;;
68;;	if (interrupted_context_in_atomic_sequence
69;;	    && interrupted_pc < atomic_exitpoint)
70;;	  interrupted_pc = atomic_entrypoint;
71;;
72;; This method is also known as gUSA ("g" User Space Atomicity) and the
73;; Linux kernel for SH3/SH4 implements support for such software atomic
74;; sequences.  It can also be implemented in freestanding environments.
75;;
76;; For this the following atomic sequence ABI is used.
77;;
78;; r15 >= 0:	Execution context is not in an atomic sequence.
79;;
80;; r15  < 0:	Execution context is in an atomic sequence and r15
81;;		holds the negative byte length of the atomic sequence.
82;;		In this case the following applies:
83;;
84;;		r0:	PC of the first instruction after the atomic
85;;			write-back instruction (exit point).
86;;			The entry point PC of the atomic sequence can be
87;;			determined by doing r0 + r15.
88;;
89;;		r1:	Saved r15 stack pointer before entering the
90;;			atomic sequence.
91;;
92;; An example atomic add sequence would look like:
93;;
94;;	mova	.Lend,r0		! .Lend must be 4-byte aligned.
95;;	mov	r15,r1
96;;	.align 2			! Insert aligning nop if needed.
97;;	mov	#(.Lstart - .Lend),r15	! Enter atomic sequence
98;;.Lstart:
99;;	mov.l	@r4,r2			! read value
100;;	add	r2,r5			! modify value
101;;	mov.l	r5,@r4			! write-back
102;;.Lend:
103;;	mov	r1,r15			! Exit atomic sequence
104;;					! r2 holds the previous value.
105;;					! r5 holds the new value.
106;;
107;; Notice that due to the restrictions of the mova instruction, the .Lend
108;; label must always be 4-byte aligned.  Aligning the .Lend label would
109;; potentially insert a nop after the write-back instruction which could
110;; make the sequence to be rewound, although it has already passed the
111;; write-back instruction.  This would make it execute twice.
112;; For correct operation the atomic sequences must not be rewound after
113;; they have passed the write-back instruction.
114;;
115;; This is model works only on SH3* and SH4* because the stack pointer (r15)
116;; is set to an invalid pointer temporarily.  SH1* and SH2* CPUs will try
117;; to push SR and PC registers on the stack when an interrupt / exception
118;; occurs, and thus require the stack pointer (r15) always to be valid.
119;;
120;;
121;; TCB Software Atomics (-matomic-model=soft-tcb)
122;;
123;; This model is a variation of the gUSA model.  The concept of rewindable
124;; atomic sequences is the same, but it does not use the stack pointer (r15)
125;; for signaling the 'is in atomic sequence' condition.  Instead, a variable
126;; in the thread control block (TCB) is set to hold the exit point of the
127;; atomic sequence.  This assumes that the GBR is used as a thread pointer
128;; register.  The offset of the variable in the TCB to be used must be
129;; specified with an additional option 'gbr-offset', such as:
130;;	-matomic-model=soft-tcb,gbr-offset=4
131;;
132;; For this model the following atomic sequence ABI is used.
133;;
134;; @(#x,gbr) == 0:  Execution context is not in an atomic sequence.
135;;
136;; @(#x,gbr) != 0:  Execution context is in an atomic sequence.  In this
137;;		    case the following applies:
138;;
139;;		    @(#x,gbr):	PC of the first instruction after the atomic
140;;				write-back instruction (exit point).
141;;
142;;		    r1:		Negative byte length of the atomic sequence.
143;;				The entry point PC of the sequence can be
144;;				determined by doing @(#x,gbr) + r1
145;;
146;; Note: #x is the user specified gbr-offset.
147;;
148;;
149;; Interrupt-Flipping Software Atomics (-matomic-model=soft-imask)
150;;
151;; This model achieves atomicity by temporarily disabling interrupts for
152;; the duration of the atomic sequence.  This works only when the program
153;; runs in privileged mode but does not require any support from the
154;; interrupt / exception handling code.  There is no particular ABI.
155;; To disable interrupts the SR.IMASK bits are set to '1111'.
156;; This method is not as efficient as the other software atomic models,
157;; since loading and storing SR (in order to flip interrupts on / off)
158;; requires using multi-cycle instructions.  Moreover, it can potentially
159;; increase the interrupt latency which might be important for hard-realtime
160;; applications.
161;;
162;;
163;; Compatibility Notes
164;;
165;; On single-core SH4A CPUs software atomic aware interrupt / exception code
166;; is actually compatible with user code that utilizes hardware atomics.
167;; Since SImode hardware atomic sequences are more compact on SH4A they are
168;; always used, regardless of the selected atomic model.  This atomic model
169;; mixing can be disabled by setting the 'strict' flag, like:
170;;	-matomic-model=soft-gusa,strict
171;;
172;; The software atomic models are generally compatible with each other,
173;; but the interrupt / exception handling code has to support both gUSA and
174;; TCB models.
175;;
176;; The current atomic support is limited to QImode, HImode and SImode
177;; atomic operations.  DImode operations could also be implemented but
178;; would require some ABI modifications to support multiple-instruction
179;; write-back.  This is because SH1/SH2/SH3/SH4 does not have a DImode
180;; store instruction.  DImode stores must be split into two SImode stores.
181
182(define_c_enum "unspec" [
183  UNSPEC_ATOMIC
184])
185
186(define_c_enum "unspecv" [
187  UNSPECV_CMPXCHG_1
188  UNSPECV_CMPXCHG_2
189  UNSPECV_CMPXCHG_3
190])
191
192(define_mode_attr i124extend_insn [(QI "exts.b") (HI "exts.w") (SI "mov")])
193
194(define_code_iterator FETCHOP [plus minus ior xor and])
195(define_code_attr fetchop_name
196  [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")])
197
198;;------------------------------------------------------------------------------
199;; comapre and swap
200
201;; Only the hard_llcs SImode patterns can use an I08 for the comparison
202;; or for the new swapped in value.
203(define_predicate "atomic_arith_operand_0"
204  (and (match_code "subreg,reg,const_int")
205       (ior (match_operand 0 "arith_reg_operand")
206	    (and (match_test "satisfies_constraint_I08 (op)")
207		 (match_test "mode == SImode")
208		 (ior (match_test "TARGET_ATOMIC_HARD_LLCS")
209		      (match_test "TARGET_ATOMIC_ANY && TARGET_SH4A
210				   && !TARGET_ATOMIC_STRICT"))))))
211
212;; Displacement addressing can be used for all SImode atomic patterns, except
213;; llcs.
214(define_predicate "atomic_mem_operand_0"
215  (and (match_code "mem")
216       (ior (match_operand 0 "simple_mem_operand")
217	    (and (match_test "mode == SImode")
218		 (and (match_test "!TARGET_ATOMIC_HARD_LLCS")
219		      (match_test "!TARGET_SH4A || TARGET_ATOMIC_STRICT"))
220		 (match_operand 0 "short_displacement_mem_operand")))))
221
222(define_expand "atomic_compare_and_swap<mode>"
223  [(match_operand:SI 0 "arith_reg_dest")		;; bool success output
224   (match_operand:QIHISI 1 "arith_reg_dest")		;; oldval output
225   (match_operand:QIHISI 2 "atomic_mem_operand_0")	;; memory
226   (match_operand:QIHISI 3 "atomic_arith_operand_0")	;; expected input
227   (match_operand:QIHISI 4 "atomic_arith_operand_0")	;; newval input
228   (match_operand:SI 5 "const_int_operand")		;; is_weak
229   (match_operand:SI 6 "const_int_operand")		;; success model
230   (match_operand:SI 7 "const_int_operand")]		;; failure model
231  "TARGET_ATOMIC_ANY"
232{
233  rtx mem = operands[2];
234  rtx old_val = gen_lowpart (SImode, operands[1]);
235  rtx exp_val = operands[3];
236  rtx new_val = operands[4];
237  rtx atomic_insn;
238
239  if (TARGET_ATOMIC_HARD_LLCS
240      || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
241    atomic_insn = gen_atomic_compare_and_swap<mode>_hard (old_val, mem,
242							  exp_val, new_val);
243  else if (TARGET_ATOMIC_SOFT_GUSA)
244    atomic_insn = gen_atomic_compare_and_swap<mode>_soft_gusa (old_val, mem,
245		      exp_val, new_val);
246  else if (TARGET_ATOMIC_SOFT_TCB)
247    atomic_insn = gen_atomic_compare_and_swap<mode>_soft_tcb (old_val, mem,
248		      exp_val, new_val, TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
249  else if (TARGET_ATOMIC_SOFT_IMASK)
250    atomic_insn = gen_atomic_compare_and_swap<mode>_soft_imask (old_val, mem,
251		      exp_val, new_val);
252  else
253    FAIL;
254
255  emit_insn (atomic_insn);
256
257  if (<MODE>mode == QImode)
258    emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[1]),
259				     operands[1]));
260  else if (<MODE>mode == HImode)
261    emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[1]),
262				     operands[1]));
263  emit_insn (gen_movsi (operands[0], gen_rtx_REG (SImode, T_REG)));
264  DONE;
265})
266
267(define_insn_and_split "atomic_compare_and_swapsi_hard"
268  [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
269	(unspec_volatile:SI
270	  [(match_operand:SI 1 "atomic_mem_operand_0" "=Sra")
271	   (match_operand:SI 2 "arith_operand" "rI08")
272	   (match_operand:SI 3 "arith_operand" "rI08")]
273	  UNSPECV_CMPXCHG_1))
274   (set (match_dup 1)
275	(unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_2))
276   (set (reg:SI T_REG)
277	(unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
278   (clobber (reg:SI R0_REG))]
279  "TARGET_ATOMIC_HARD_LLCS
280   || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
281{
282  return "\r0:	movli.l	%1,r0"		"\n"
283	 "	cmp/eq	%2,r0"		"\n"
284	 "	bf{.|/}s	0f"	"\n"
285	 "	mov	r0,%0"		"\n"
286	 "	mov	%3,r0"		"\n"
287	 "	movco.l	r0,%1"		"\n"
288	 "	bf	0b"		"\n"
289	 "0:";
290}
291  "&& can_create_pseudo_p () && !satisfies_constraint_I08 (operands[2])"
292  [(const_int 0)]
293{
294  /* FIXME: Sometimes the 'expected value' operand is not propagated as
295     immediate value.  See PR 64974.  */
296  set_of_reg op2 = sh_find_set_of_reg (operands[2], curr_insn,
297				       prev_nonnote_nondebug_insn_bb);
298  if (op2.set_src != NULL && satisfies_constraint_I08 (op2.set_src))
299    {
300      rtx* r = &XVECEXP (XEXP (XVECEXP (PATTERN (curr_insn), 0, 0), 1), 0, 1);
301      validate_change (curr_insn, r, op2.set_src, false);
302      DONE;
303    }
304  else
305    FAIL;
306}
307  [(set_attr "length" "14")])
308
309;; The QIHImode llcs patterns modify the address register of the memory
310;; operand.  In order to express that, we have to open code the memory
311;; operand.  Initially the insn is expanded like every other atomic insn
312;; using the memory operand.  In split1 the insn is converted and the
313;; memory operand's address register is exposed.
314(define_insn_and_split "atomic_compare_and_swap<mode>_hard"
315  [(set (match_operand:SI 0 "arith_reg_dest")
316	(unspec_volatile:SI
317	  [(match_operand:QIHI 1 "atomic_mem_operand_0")
318	   (match_operand:QIHI 2 "arith_reg_operand")
319	   (match_operand:QIHI 3 "arith_reg_operand")]
320	  UNSPECV_CMPXCHG_1))
321   (set (match_dup 1)
322	(unspec_volatile:QIHI [(const_int 0)] UNSPECV_CMPXCHG_2))
323   (set (reg:SI T_REG)
324	(unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
325   (clobber (reg:SI R0_REG))]
326  "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
327  "#"
328  "&& 1"
329  [(const_int 0)]
330{
331  rtx i = gen_atomic_compare_and_swap<mode>_hard_1 (
332		operands[0], XEXP (operands[1], 0), operands[2], operands[3]);
333
334  /* Replace the new mems in the new insn with the old mem to preserve
335     aliasing info.  */
336  XVECEXP (XEXP (XVECEXP (i, 0, 0), 1), 0, 0) = operands[1];
337  XEXP (XVECEXP (i, 0, 1), 0) = operands[1];
338  emit_insn (i);
339})
340
341(define_insn "atomic_compare_and_swap<mode>_hard_1"
342  [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
343	(unspec_volatile:SI
344	  [(mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
345	   (match_operand:QIHI 2 "arith_reg_operand" "r")
346	   (match_operand:QIHI 3 "arith_reg_operand" "r")]
347	  UNSPECV_CMPXCHG_1))
348   (set (mem:QIHI (match_dup 1))
349	(unspec_volatile:QIHI [(const_int 0)] UNSPECV_CMPXCHG_2))
350   (set (reg:SI T_REG)
351	(unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
352   (clobber (reg:SI R0_REG))
353   (clobber (match_scratch:SI 4 "=&r"))
354   (clobber (match_scratch:SI 5 "=&r"))
355   (clobber (match_scratch:SI 6 "=1"))]
356  "TARGET_ATOMIC_HARD_LLCS"
357{
358  return "\r	mov	#-4,%5"			"\n"
359	 "	<i124extend_insn>	%2,%4"	"\n"
360	 "	and	%1,%5"			"\n"
361	 "	xor	%5,%1"			"\n"
362	 "	add	r15,%1"			"\n"
363	 "	add	#-4,%1"			"\n"
364	 "0:	movli.l	@%5,r0"			"\n"
365	 "	mov.l	r0,@-r15"		"\n"
366	 "	mov.<bw>	@%1,%0"		"\n"
367	 "	mov.<bw>	%3,@%1"		"\n"
368	 "	cmp/eq	%4,%0"			"\n"
369	 "	bf{.|/}s	0f"		"\n"
370	 "	mov.l	@r15+,r0"		"\n"
371	 "	movco.l	r0,@%5"			"\n"
372	 "	bf	0b"			"\n"
373	 "0:";
374}
375  [(set_attr "length" "30")])
376
377(define_insn "atomic_compare_and_swap<mode>_soft_gusa"
378  [(set (match_operand:SI 0 "arith_reg_dest" "=&u")
379	(unspec_volatile:SI
380	  [(match_operand:QIHISI 1 "atomic_mem_operand_0" "=AraAdd")
381	   (match_operand:QIHISI 2 "arith_reg_operand" "u")
382	   (match_operand:QIHISI 3 "arith_reg_operand" "u")]
383	  UNSPECV_CMPXCHG_1))
384   (set (match_dup 1)
385	(unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
386   (set (reg:SI T_REG)
387	(unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
388   (clobber (match_scratch:SI 4 "=&u"))
389   (clobber (reg:SI R0_REG))
390   (clobber (reg:SI R1_REG))]
391  "TARGET_ATOMIC_SOFT_GUSA"
392{
393  return "\r	mova	1f,r0"			"\n"
394	 "	<i124extend_insn>	%2,%4"	"\n"
395	 "	.align 2"			"\n"
396	 "	mov	r15,r1"			"\n"
397	 "	mov	#(0f-1f),r15"		"\n"
398	 "0:	mov.<bwl>	%1,%0"		"\n"
399	 "	cmp/eq	%0,%4"			"\n"
400	 "	bf	1f"			"\n"
401	 "	mov.<bwl>	%3,%1"		"\n"
402	 "1:	mov	r1,r15";
403}
404  [(set_attr "length" "20")])
405
406(define_insn "atomic_compare_and_swap<mode>_soft_tcb"
407  [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
408	(unspec_volatile:SI
409	  [(match_operand:QIHISI 1 "atomic_mem_operand_0" "=SraSdd")
410	   (match_operand:QIHISI 2 "arith_reg_operand" "r")
411	   (match_operand:QIHISI 3 "arith_reg_operand" "r")]
412	  UNSPECV_CMPXCHG_1))
413   (set (match_dup 1)
414	(unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
415   (set (reg:SI T_REG)
416	(unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
417   (use (match_operand:SI 4 "gbr_displacement"))
418   (clobber (match_scratch:SI 5 "=&r"))
419   (clobber (reg:SI R0_REG))
420   (clobber (reg:SI R1_REG))]
421  "TARGET_ATOMIC_SOFT_TCB"
422{
423  return "\r	mova	1f,r0"			"\n"
424	 "	.align 2"			"\n"
425	 "	<i124extend_insn>	%2,%5"	"\n"
426	 "	mov	#(0f-1f),r1"		"\n"
427	 "	mov.l	r0,@(%O4,gbr)"		"\n"
428	 "0:	mov.<bwl>	%1,%0"		"\n"
429	 "	mov	#0,r0"			"\n"
430	 "	cmp/eq	%0,%5"			"\n"
431	 "	bf	1f"			"\n"
432	 "	mov.<bwl>	%3,%1"		"\n"
433	 "1:	mov.l	r0,@(%O4,gbr)";
434}
435  [(set_attr "length" "22")])
436
437(define_insn "atomic_compare_and_swap<mode>_soft_imask"
438  [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
439	(unspec_volatile:SI
440	  [(match_operand:QIHISI 1 "atomic_mem_operand_0" "=SraSdd")
441	   (match_operand:QIHISI 2 "arith_reg_operand" "r")
442	   (match_operand:QIHISI 3 "arith_reg_operand" "r")]
443	  UNSPECV_CMPXCHG_1))
444   (set (match_dup 1)
445	(unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
446   (set (reg:SI T_REG)
447	(unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
448   (clobber (match_scratch:SI 4 "=&r"))
449   (clobber (match_scratch:SI 5 "=&r"))]
450  "TARGET_ATOMIC_SOFT_IMASK"
451{
452  /* The comparison result is supposed to be in T_REG.
453     Notice that restoring SR will overwrite the T_REG.  We handle this by
454     rotating the T_REG into the saved SR before restoring SR.  On SH2A we
455     can do one insn shorter by using the bst insn.  */
456  if (!TARGET_SH2A)
457    return "\r	stc	sr,%0"			"\n"
458	   "	<i124extend_insn>	%2,%4"	"\n"
459	   "	mov	%0,%5"			"\n"
460	   "	or	#0xF0,%0"		"\n"
461	   "	shlr	%5"			"\n"
462	   "	ldc	%0,sr"			"\n"
463	   "	mov.<bwl>	%1,%0"		"\n"
464	   "	cmp/eq	%4,%0"			"\n"
465	   "	bf	1f"			"\n"
466	   "	mov.<bwl>	%3,%1"		"\n"
467	   "1:	rotcl	%5"			"\n"
468	   "	ldc	%5,sr";
469  else
470    return "\r	stc	sr,%0"			"\n"
471	   "	<i124extend_insn>	%2,%4"	"\n"
472	   "	mov	%0,%5"			"\n"
473	   "	or	#0xF0,%0"		"\n"
474	   "	ldc	%0,sr"			"\n"
475	   "	mov.<bwl>	%1,%0"		"\n"
476	   "	cmp/eq	%4,%0"			"\n"
477	   "	bst	#0,%5"			"\n"
478	   "	bf	1f"			"\n"
479	   "	mov.<bwl>	%3,%1"		"\n"
480	   "1:	ldc	%5,sr";
481}
482  [(set (attr "length") (if_then_else (match_test "!TARGET_SH2A")
483				      (const_string "24")
484				      (const_string "22")))])
485
486;;------------------------------------------------------------------------------
487;; read - write - return old value
488
489(define_expand "atomic_exchange<mode>"
490  [(match_operand:QIHISI 0 "arith_reg_dest")		;; oldval output
491   (match_operand:QIHISI 1 "atomic_mem_operand_0")	;; memory
492   (match_operand:QIHISI 2 "atomic_arith_operand_0")	;; newval input
493   (match_operand:SI 3 "const_int_operand")]		;; memory model
494  "TARGET_ATOMIC_ANY"
495{
496  rtx mem = operands[1];
497  rtx val = operands[2];
498  rtx atomic_insn;
499
500  if (TARGET_ATOMIC_HARD_LLCS
501      || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
502    atomic_insn = gen_atomic_exchange<mode>_hard (operands[0], mem, val);
503  else if (TARGET_ATOMIC_SOFT_GUSA)
504    atomic_insn = gen_atomic_exchange<mode>_soft_gusa (operands[0], mem, val);
505  else if (TARGET_ATOMIC_SOFT_TCB)
506    atomic_insn = gen_atomic_exchange<mode>_soft_tcb (operands[0], mem, val,
507		      TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
508  else if (TARGET_ATOMIC_SOFT_IMASK)
509    atomic_insn = gen_atomic_exchange<mode>_soft_imask (operands[0], mem, val);
510  else
511    FAIL;
512
513  emit_insn (atomic_insn);
514
515  if (<MODE>mode == QImode)
516    emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
517				     operands[0]));
518  else if (<MODE>mode == HImode)
519    emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
520				     operands[0]));
521  DONE;
522})
523
524(define_insn "atomic_exchangesi_hard"
525  [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
526	(match_operand:SI 1 "atomic_mem_operand_0" "=Sra"))
527   (set (match_dup 1)
528	(unspec:SI
529	  [(match_operand:SI 2 "arith_operand" "rI08")] UNSPEC_ATOMIC))
530   (set (reg:SI T_REG) (const_int 1))
531   (clobber (reg:SI R0_REG))]
532  "TARGET_ATOMIC_HARD_LLCS
533   || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
534{
535  return "\r0:	movli.l	%1,r0"		"\n"
536	 "	mov	r0,%0"		"\n"
537	 "	mov	%2,r0"		"\n"
538	 "	movco.l r0,%1"		"\n"
539	 "	bf	0b";
540}
541  [(set_attr "length" "10")])
542
543;; The QIHImode llcs patterns modify the address register of the memory
544;; operand.  In order to express that, we have to open code the memory
545;; operand.  Initially the insn is expanded like every other atomic insn
546;; using the memory operand.  In split1 the insn is converted and the
547;; memory operand's address register is exposed.
548(define_insn_and_split "atomic_exchange<mode>_hard"
549  [(set (match_operand:QIHI 0 "arith_reg_dest")
550	(match_operand:QIHI 1 "atomic_mem_operand_0"))
551   (set (match_dup 1)
552	(unspec:QIHI
553	  [(match_operand:QIHI 2 "arith_reg_operand")] UNSPEC_ATOMIC))
554   (set (reg:SI T_REG) (const_int 1))
555   (clobber (reg:SI R0_REG))]
556  "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
557  "#"
558  "&& 1"
559  [(const_int 0)]
560{
561  rtx i = gen_atomic_exchange<mode>_hard_1 (operands[0], XEXP (operands[1], 0),
562					    operands[2]);
563
564  /* Replace the new mems in the new insn with the old mem to preserve
565     aliasing info.  */
566  XEXP (XVECEXP (i, 0, 0), 1) = operands[1];
567  XEXP (XVECEXP (i, 0, 1), 0) = operands[1];
568  emit_insn (i);
569})
570
571(define_insn "atomic_exchange<mode>_hard_1"
572  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
573	(mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
574   (set (mem:QIHI (match_dup 1))
575	(unspec:QIHI
576	  [(match_operand:QIHI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC))
577   (set (reg:SI T_REG) (const_int 1))
578   (clobber (reg:SI R0_REG))
579   (clobber (match_scratch:SI 3 "=&r"))
580   (clobber (match_scratch:SI 4 "=1"))]
581  "TARGET_ATOMIC_HARD_LLCS"
582{
583  return "\r	mov	#-4,%3"			"\n"
584	 "	and	%1,%3"			"\n"
585	 "	xor	%3,%1"			"\n"
586	 "	add	r15,%1"			"\n"
587	 "	add	#-4,%1"			"\n"
588	 "0:	movli.l	@%3,r0"			"\n"
589	 "	mov.l	r0,@-r15"		"\n"
590	 "	mov.<bw>	@%1,%0"		"\n"
591	 "	mov.<bw>	%2,@%1" 	"\n"
592	 "	mov.l	@r15+,r0"		"\n"
593	 "	movco.l	r0,@%3"			"\n"
594	 "	bf	0b";
595}
596  [(set_attr "length" "24")])
597
598(define_insn "atomic_exchange<mode>_soft_gusa"
599  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
600	(match_operand:QIHISI 1 "atomic_mem_operand_0" "=AraAdd"))
601   (set (match_dup 1)
602	(unspec:QIHISI
603	  [(match_operand:QIHISI 2 "arith_reg_operand" "u")] UNSPEC_ATOMIC))
604   (clobber (reg:SI R0_REG))
605   (clobber (reg:SI R1_REG))]
606  "TARGET_ATOMIC_SOFT_GUSA"
607{
608  return "\r	mova	1f,r0"			"\n"
609	 "	.align 2"			"\n"
610	 "	mov	r15,r1"			"\n"
611	 "	mov	#(0f-1f),r15"		"\n"
612	 "0:	mov.<bwl>	%1,%0"		"\n"
613	 "	mov.<bwl>	%2,%1"		"\n"
614	 "1:	mov	r1,r15";
615}
616  [(set_attr "length" "14")])
617
618(define_insn "atomic_exchange<mode>_soft_tcb"
619  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
620	(match_operand:QIHISI 1 "atomic_mem_operand_0" "=SraSdd"))
621   (set (match_dup 1)
622	(unspec:QIHISI
623	  [(match_operand:QIHISI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC))
624   (clobber (reg:SI R0_REG))
625   (clobber (reg:SI R1_REG))
626   (use (match_operand:SI 3 "gbr_displacement"))]
627  "TARGET_ATOMIC_SOFT_TCB"
628{
629  return "\r	mova	1f,r0"			"\n"
630	 "	mov	#(0f-1f),r1"		"\n"
631	 "	.align 2"			"\n"
632	 "	mov.l	r0,@(%O3,gbr)"		"\n"
633	 "0:	mov.<bwl>	%1,%0"		"\n"
634	 "	mov	#0,r0"			"\n"
635	 "	mov.<bwl>	%2,%1"		"\n"
636	 "1:	mov.l	r0,@(%O3,gbr)";
637}
638  [(set_attr "length" "16")])
639
640(define_insn "atomic_exchange<mode>_soft_imask"
641  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
642	(match_operand:QIHISI 1 "atomic_mem_operand_0" "=SraSdd"))
643   (set (match_dup 1)
644	(unspec:QIHISI
645	  [(match_operand:QIHISI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC))
646   (clobber (match_scratch:SI 3 "=&r"))]
647  "TARGET_ATOMIC_SOFT_IMASK"
648{
649  return "\r	stc	sr,%0"			"\n"
650	 "	mov	%0,%3"			"\n"
651	 "	or	#0xF0,%0"		"\n"
652	 "	ldc	%0,sr"			"\n"
653	 "	mov.<bwl>	%1,%0"		"\n"
654	 "	mov.<bwl>	%2,%1"		"\n"
655	 "	ldc	%3,sr";
656}
657  [(set_attr "length" "14")])
658
659;;------------------------------------------------------------------------------
660;; read - add|sub|or|and|xor|nand - write - return old value
661
662;; atomic_arith_operand_1 can be used by any atomic type for a plus op,
663;; since there's no r0 restriction.
664(define_predicate "atomic_arith_operand_1"
665  (and (match_code "subreg,reg,const_int")
666       (ior (match_operand 0 "arith_reg_operand")
667	    (match_test "satisfies_constraint_I08 (op)"))))
668
669;; atomic_logic_operand_1 can be used by the hard_llcs, tcb and soft_imask
670;; patterns only due to its r0 restriction.
671(define_predicate "atomic_logical_operand_1"
672  (and (match_code "subreg,reg,const_int")
673       (ior (match_operand 0 "arith_reg_operand")
674	    (and (match_test "satisfies_constraint_K08 (op)")
675		 (ior (match_test "TARGET_ATOMIC_HARD_LLCS")
676		      (match_test "TARGET_ATOMIC_SOFT_IMASK")
677		      (match_test "TARGET_ATOMIC_SOFT_TCB")
678		      (match_test "TARGET_ATOMIC_ANY && TARGET_SH4A
679				   && mode == SImode
680				   && !TARGET_ATOMIC_STRICT"))))))
681
682(define_code_attr fetchop_predicate_1
683  [(plus "atomic_arith_operand_1") (minus "arith_reg_operand")
684   (ior "atomic_logical_operand_1") (xor "atomic_logical_operand_1")
685   (and "atomic_logical_operand_1")])
686
687(define_code_attr fetchop_constraint_1_llcs
688  [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
689
690(define_code_attr fetchop_constraint_1_gusa
691  [(plus "uI08") (minus "u") (ior "u") (xor "u") (and "u")])
692
693(define_code_attr fetchop_constraint_1_tcb
694  [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
695
696(define_code_attr fetchop_constraint_1_imask
697  [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
698
699;; Displacement addressing mode (incl. GBR relative) can be used by tcb and
700;; imask atomic patterns in any mode, since all the patterns use R0 as the
701;; register operand for memory loads/stores.  gusa and llcs patterns can only
702;; use displacement addressing for SImode.
703(define_predicate "atomic_mem_operand_1"
704  (and (match_code "mem")
705       (ior (match_operand 0 "simple_mem_operand")
706	    (and (match_test "mode == SImode")
707		 (match_test "TARGET_ATOMIC_SOFT_GUSA
708			      && (!TARGET_SH4A || TARGET_ATOMIC_STRICT)")
709		 (match_operand 0 "short_displacement_mem_operand"))
710	    (and (ior (match_test "(TARGET_ATOMIC_SOFT_TCB
711				    || TARGET_ATOMIC_SOFT_IMASK)
712				   && (!TARGET_SH4A || TARGET_ATOMIC_STRICT)")
713		      (match_test "(TARGET_ATOMIC_SOFT_TCB
714				    || TARGET_ATOMIC_SOFT_IMASK)
715				   && TARGET_SH4A && !TARGET_ATOMIC_STRICT
716				   && mode != SImode"))
717		 (ior (match_operand 0 "short_displacement_mem_operand")
718		      (match_operand 0 "gbr_address_mem"))))))
719
720(define_expand "atomic_fetch_<fetchop_name><mode>"
721  [(set (match_operand:QIHISI 0 "arith_reg_dest")
722	(match_operand:QIHISI 1 "atomic_mem_operand_1"))
723   (set (match_dup 1)
724	(unspec:QIHISI
725	  [(FETCHOP:QIHISI (match_dup 1)
726	     (match_operand:QIHISI 2 "<fetchop_predicate_1>"))]
727	  UNSPEC_ATOMIC))
728   (match_operand:SI 3 "const_int_operand")]
729  "TARGET_ATOMIC_ANY"
730{
731  rtx mem = operands[1];
732  rtx atomic_insn;
733
734  if (TARGET_ATOMIC_HARD_LLCS
735      || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
736    atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_hard (operands[0], mem,
737							      operands[2]);
738  else if (TARGET_ATOMIC_SOFT_GUSA)
739    atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_gusa (operands[0],
740		      mem, operands[2]);
741  else if (TARGET_ATOMIC_SOFT_TCB)
742    atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_tcb (operands[0],
743		      mem, operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
744  else if (TARGET_ATOMIC_SOFT_IMASK)
745    atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_imask (operands[0],
746		      mem, operands[2]);
747  else
748    FAIL;
749
750  emit_insn (atomic_insn);
751
752  if (<MODE>mode == QImode)
753    emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
754				     operands[0]));
755  else if (<MODE>mode == HImode)
756    emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
757				     operands[0]));
758  DONE;
759})
760
761(define_insn_and_split "atomic_fetch_<fetchop_name>si_hard"
762  [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
763	(match_operand:SI 1 "atomic_mem_operand_1" "=Sra"))
764   (set (match_dup 1)
765	(unspec:SI
766	  [(FETCHOP:SI (match_dup 1)
767		       (match_operand:SI 2 "<fetchop_predicate_1>"
768					   "<fetchop_constraint_1_llcs>"))]
769	  UNSPEC_ATOMIC))
770   (set (reg:SI T_REG) (const_int 1))
771   (clobber (reg:SI R0_REG))]
772  "TARGET_ATOMIC_HARD_LLCS
773   || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
774{
775  return "\r0:	movli.l	%1,r0"		"\n"
776	 "	mov	r0,%0"		"\n"
777	 "	<fetchop_name>	%2,r0"	"\n"
778	 "	movco.l	r0,%1"		"\n"
779	 "	bf	0b";
780}
781  "&& can_create_pseudo_p () && optimize
782   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
783  [(const_int 0)]
784{
785  emit_insn (gen_atomic_<fetchop_name>_fetchsi_hard (gen_reg_rtx (SImode),
786						     operands[1], operands[2]));
787}
788  [(set_attr "length" "10")])
789
790;; Combine pattern for xor (val, -1) / nand (val, -1).
791(define_insn_and_split "atomic_fetch_notsi_hard"
792  [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
793	(match_operand:SI 1 "atomic_mem_operand_1" "=Sra"))
794   (set (match_dup 1)
795	(unspec:SI [(not:SI (match_dup 1))] UNSPEC_ATOMIC))
796   (set (reg:SI T_REG) (const_int 1))
797   (clobber (reg:SI R0_REG))]
798  "TARGET_ATOMIC_HARD_LLCS
799   || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
800{
801  return "\r0:	movli.l	%1,r0"		"\n"
802	 "	mov	r0,%0"		"\n"
803	 "	not	r0,r0"		"\n"
804	 "	movco.l	r0,%1"		"\n"
805	 "	bf	0b";
806}
807  "&& can_create_pseudo_p () && optimize
808   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
809  [(const_int 0)]
810{
811  emit_insn (gen_atomic_not_fetchsi_hard (gen_reg_rtx (SImode), operands[1]));
812}
813  [(set_attr "length" "10")])
814
815;; The QIHImode llcs patterns modify the address register of the memory
816;; operand.  In order to express that, we have to open code the memory
817;; operand.  Initially the insn is expanded like every other atomic insn
818;; using the memory operand.  In split1 the insn is converted and the
819;; memory operand's address register is exposed.
820(define_insn_and_split "atomic_fetch_<fetchop_name><mode>_hard"
821  [(set (match_operand:QIHI 0 "arith_reg_dest")
822	(match_operand:QIHI 1 "atomic_mem_operand_1"))
823   (set (match_dup 1)
824	(unspec:QIHI
825	  [(FETCHOP:QIHI (match_dup 1)
826			 (match_operand:QIHI 2 "<fetchop_predicate_1>"))]
827	  UNSPEC_ATOMIC))
828   (set (reg:SI T_REG) (const_int 1))
829   (clobber (reg:SI R0_REG))]
830  "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
831  "#"
832  "&& 1"
833  [(const_int 0)]
834{
835  if (optimize
836      && sh_reg_dead_or_unused_after_insn (curr_insn, REGNO (operands[0])))
837    emit_insn (gen_atomic_<fetchop_name><mode>_hard (operands[1], operands[2]));
838  else
839    {
840      rtx i = gen_atomic_fetch_<fetchop_name><mode>_hard_1 (
841			operands[0], XEXP (operands[1], 0), operands[2]);
842
843      /* Replace the new mems in the new insn with the old mem to preserve
844	 aliasing info.  */
845      XEXP (XVECEXP (i, 0, 0), 1) = operands[1];
846      XEXP (XVECEXP (i, 0, 1), 0) = operands[1];
847      XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 1), 1), 0, 0), 0) = operands[1];
848      emit_insn (i);
849    }
850})
851
852(define_insn "atomic_fetch_<fetchop_name><mode>_hard_1"
853  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
854	(mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
855   (set (mem:QIHI (match_dup 1))
856	(unspec:QIHI
857	  [(FETCHOP:QIHI (mem:QIHI (match_dup 1))
858			 (match_operand:QIHI 2 "<fetchop_predicate_1>"
859					       "<fetchop_constraint_1_llcs>"))]
860	  UNSPEC_ATOMIC))
861   (set (reg:SI T_REG) (const_int 1))
862   (clobber (reg:SI R0_REG))
863   (clobber (match_scratch:SI 3 "=&r"))
864   (clobber (match_scratch:SI 4 "=1"))]
865  "TARGET_ATOMIC_HARD_LLCS"
866{
867  return "\r	mov	#-4,%3"			"\n"
868	 "	and	%1,%3"			"\n"
869	 "	xor	%3,%1"			"\n"
870	 "	add	r15,%1"			"\n"
871	 "	add	#-4,%1"			"\n"
872	 "0:	movli.l	@%3,r0"			"\n"
873	 "	mov.l	r0,@-r15"		"\n"
874	 "	mov.<bw>	@%1,r0"		"\n"
875	 "	mov	r0,%0"			"\n"
876	 "	<fetchop_name>	%2,r0"		"\n"
877	 "	mov.<bw>	r0,@%1"		"\n"
878	 "	mov.l	@r15+,r0"		"\n"
879	 "	movco.l	r0,@%3"			"\n"
880	 "	bf	0b";
881}
882  [(set_attr "length" "28")])
883
884;; The QIHImode llcs patterns modify the address register of the memory
885;; operand.  In order to express that, we have to open code the memory
886;; operand.  Initially the insn is expanded like every other atomic insn
887;; using the memory operand.  In split1 the insn is converted and the
888;; memory operand's address register is exposed.
889(define_insn_and_split "atomic_<fetchop_name><mode>_hard"
890  [(set (match_operand:QIHI 0 "atomic_mem_operand_1")
891	(unspec:QIHI
892	  [(FETCHOP:QIHI (match_dup 0)
893			 (match_operand:QIHI 1 "<fetchop_predicate_1>"))]
894	  UNSPEC_ATOMIC))
895   (set (reg:SI T_REG) (const_int 1))
896   (clobber (reg:SI R0_REG))]
897  "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
898  "#"
899  "&& 1"
900  [(const_int 0)]
901{
902  rtx i = gen_atomic_<fetchop_name><mode>_hard_1 (XEXP (operands[0], 0),
903						  operands[1]);
904  /* Replace the new mems in the new insn with the old mem to preserve
905     aliasing info.  */
906  XEXP (XVECEXP (i, 0, 0), 0) = operands[0];
907  XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 0), 1), 0, 0), 0) = operands[0];
908  emit_insn (i);
909})
910
911(define_insn "atomic_<fetchop_name><mode>_hard_1"
912  [(set (mem:QIHI (match_operand:SI 0 "arith_reg_operand" "r"))
913	(unspec:QIHI
914	  [(FETCHOP:QIHI (mem:QIHI (match_dup 0))
915			 (match_operand:QIHI 1 "<fetchop_predicate_1>"
916					       "<fetchop_constraint_1_llcs>"))]
917	  UNSPEC_ATOMIC))
918   (set (reg:SI T_REG) (const_int 1))
919   (clobber (reg:SI R0_REG))
920   (clobber (match_scratch:SI 2 "=&r"))
921   (clobber (match_scratch:SI 3 "=0"))]
922  "TARGET_ATOMIC_HARD_LLCS"
923{
924  return "\r	mov	#-4,%2"			"\n"
925	 "	and	%0,%2"			"\n"
926	 "	xor	%2,%0"			"\n"
927	 "	add	r15,%0"			"\n"
928	 "	add	#-4,%0"			"\n"
929	 "0:	movli.l	@%2,r0"			"\n"
930	 "	mov.l	r0,@-r15"		"\n"
931	 "	mov.<bw>	@%0,r0"		"\n"
932	 "	<fetchop_name>	%1,r0"		"\n"
933	 "	mov.<bw>	r0,@%0"		"\n"
934	 "	mov.l	@r15+,r0"		"\n"
935	 "	movco.l	r0,@%2"			"\n"
936	 "	bf	0b";
937}
938  [(set_attr "length" "26")])
939
940;; Combine pattern for xor (val, -1) / nand (val, -1).
941(define_insn_and_split "atomic_fetch_not<mode>_hard"
942  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
943	(mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
944   (set (mem:QIHI (match_dup 1))
945	(unspec:QIHI [(not:QIHI (mem:QIHI (match_dup 1)))] UNSPEC_ATOMIC))
946   (set (reg:SI T_REG) (const_int 1))
947   (clobber (reg:SI R0_REG))
948   (clobber (match_scratch:SI 2 "=&r"))
949   (clobber (match_scratch:SI 3 "=1"))]
950  "TARGET_ATOMIC_HARD_LLCS"
951{
952  return "\r	mov	#-4,%2"			"\n"
953	 "	and	%1,%2"			"\n"
954	 "	xor	%2,%1"			"\n"
955	 "	add	r15,%1"			"\n"
956	 "	add	#-4,%1"			"\n"
957	 "0:	movli.l	@%2,r0"			"\n"
958	 "	mov.l	r0,@-r15"		"\n"
959	 "	mov.<bw>	@%1,%0"		"\n"
960	 "	not	%0,r0"			"\n"
961	 "	mov.<bw>	r0,@%1"		"\n"
962	 "	mov.l	@r15+,r0"		"\n"
963	 "	movco.l	r0,@%2"			"\n"
964	 "	bf	0b";
965}
966  "&& can_create_pseudo_p () && optimize
967   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
968  [(const_int 0)]
969{
970  rtx i = gen_atomic_not<mode>_hard (operands[1]);
971
972  /* Replace the new mems in the new insn with the old mem to preserve
973     aliasing info.  */
974  rtx m = XEXP (XVECEXP (PATTERN (curr_insn), 0, 0), 1);
975  XEXP (XVECEXP (i, 0, 0), 0) = m;
976  XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 0), 1), 0, 0), 0) = m;
977  emit_insn (i);
978}
979  [(set_attr "length" "26")])
980
981(define_insn "atomic_not<mode>_hard"
982  [(set (mem:QIHI (match_operand:SI 0 "arith_reg_operand" "r"))
983	(unspec:QIHI [(not:QIHI (mem:QIHI (match_dup 0)))] UNSPEC_ATOMIC))
984   (set (reg:SI T_REG) (const_int 1))
985   (clobber (reg:SI R0_REG))
986   (clobber (match_scratch:SI 1 "=&r"))
987   (clobber (match_scratch:SI 2 "=0"))]
988  "TARGET_ATOMIC_HARD_LLCS"
989{
990  return "\r	mov	#-4,%1"			"\n"
991	 "	and	%0,%1"			"\n"
992	 "	xor	%1,%0"			"\n"
993	 "	add	r15,%0"			"\n"
994	 "	add	#-4,%0"			"\n"
995	 "0:	movli.l	@%1,r0"			"\n"
996	 "	mov.l	r0,@-r15"		"\n"
997	 "	mov.<bw>	@%0,r0"		"\n"
998	 "	not	r0,r0"			"\n"
999	 "	mov.<bw>	r0,@%0"		"\n"
1000	 "	mov.l	@r15+,r0"		"\n"
1001	 "	movco.l	r0,@%1"			"\n"
1002	 "	bf	0b";
1003}
1004  [(set_attr "length" "26")])
1005
1006(define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_gusa"
1007  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1008	(match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd"))
1009   (set (match_dup 1)
1010	(unspec:QIHISI
1011	  [(FETCHOP:QIHISI
1012		(match_dup 1)
1013		(match_operand:QIHISI 2 "<fetchop_predicate_1>"
1014					"<fetchop_constraint_1_gusa>"))]
1015	  UNSPEC_ATOMIC))
1016   (clobber (match_scratch:QIHISI 3 "=&u"))
1017   (clobber (reg:SI R0_REG))
1018   (clobber (reg:SI R1_REG))]
1019  "TARGET_ATOMIC_SOFT_GUSA"
1020{
1021  return "\r	mova	1f,r0"			"\n"
1022	 "	.align 2"			"\n"
1023	 "	mov	r15,r1"			"\n"
1024	 "	mov	#(0f-1f),r15"		"\n"
1025	 "0:	mov.<bwl>	%1,%0"		"\n"
1026	 "	mov	%0,%3"			"\n"
1027	 "	<fetchop_name>	%2,%3"		"\n"
1028	 "	mov.<bwl>	%3,%1"		"\n"
1029	 "1:	mov	r1,r15";
1030}
1031  "&& can_create_pseudo_p () && optimize
1032   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1033  [(const_int 0)]
1034{
1035  emit_insn (gen_atomic_<fetchop_name>_fetch<mode>_soft_gusa (
1036		gen_reg_rtx (<MODE>mode), operands[1], operands[2]));
1037}
1038  [(set_attr "length" "18")])
1039
1040;; Combine pattern for xor (val, -1) / nand (val, -1).
1041(define_insn_and_split "atomic_fetch_not<mode>_soft_gusa"
1042  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1043	(match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd"))
1044   (set (match_dup 1)
1045	(unspec:QIHISI [(not:QIHISI (match_dup 1))] UNSPEC_ATOMIC))
1046   (clobber (match_scratch:QIHISI 2 "=&u"))
1047   (clobber (reg:SI R0_REG))
1048   (clobber (reg:SI R1_REG))]
1049  "TARGET_ATOMIC_SOFT_GUSA"
1050{
1051  return "\r	mova	1f,r0"			"\n"
1052	 "	mov	r15,r1"			"\n"
1053	 "	.align 2"			"\n"
1054	 "	mov	#(0f-1f),r15"		"\n"
1055	 "0:	mov.<bwl>	%1,%0"		"\n"
1056	 "	not	%0,%2"			"\n"
1057	 "	mov.<bwl>	%2,%1"		"\n"
1058	 "1:	mov	r1,r15";
1059}
1060  "&& can_create_pseudo_p () && optimize
1061   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1062  [(const_int 0)]
1063{
1064  emit_insn (gen_atomic_not_fetch<mode>_soft_gusa (gen_reg_rtx (<MODE>mode),
1065						   operands[1]));
1066}
1067  [(set_attr "length" "16")])
1068
1069(define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_tcb"
1070  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1071	(match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd"))
1072   (set (match_dup 1)
1073	(unspec:QIHISI
1074	  [(FETCHOP:QIHISI
1075		(match_dup 1)
1076		(match_operand:QIHISI 2 "<fetchop_predicate_1>"
1077					"<fetchop_constraint_1_tcb>"))]
1078	  UNSPEC_ATOMIC))
1079   (use (match_operand:SI 3 "gbr_displacement"))
1080   (clobber (reg:SI R0_REG))
1081   (clobber (reg:SI R1_REG))]
1082  "TARGET_ATOMIC_SOFT_TCB"
1083{
1084  return "\r	mova	1f,r0"			"\n"
1085	 "	.align 2"			"\n"
1086	 "	mov	#(0f-1f),r1"		"\n"
1087	 "	mov.l	r0,@(%O3,gbr)"		"\n"
1088	 "0:	mov.<bwl>	%1,r0"		"\n"
1089	 "	mov	r0,%0"			"\n"
1090	 "	<fetchop_name>	%2,r0"		"\n"
1091	 "	mov.<bwl>	r0,%1"		"\n"
1092	 "1:	mov	#0,r0"			"\n"
1093	 "	mov.l	r0,@(%O3,gbr)";
1094}
1095  "&& can_create_pseudo_p () && optimize
1096   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1097  [(const_int 0)]
1098{
1099  emit_insn (gen_atomic_<fetchop_name><mode>_soft_tcb (
1100					operands[1], operands[2], operands[3]));
1101}
1102  [(set_attr "length" "20")])
1103
1104(define_insn "atomic_<fetchop_name><mode>_soft_tcb"
1105  [(set (match_operand:QIHISI 0 "atomic_mem_operand_1" "=SraSdd")
1106	(unspec:QIHISI
1107	  [(FETCHOP:QIHISI
1108		(match_dup 0)
1109		(match_operand:QIHISI 1 "<fetchop_predicate_1>"
1110					"<fetchop_constraint_1_tcb>"))]
1111	  UNSPEC_ATOMIC))
1112   (use (match_operand:SI 2 "gbr_displacement"))
1113   (clobber (reg:SI R0_REG))
1114   (clobber (reg:SI R1_REG))]
1115  "TARGET_ATOMIC_SOFT_TCB"
1116{
1117  return "\r	mova	1f,r0"			"\n"
1118	 "	mov	#(0f-1f),r1"		"\n"
1119	 "	.align 2"			"\n"
1120	 "	mov.l	r0,@(%O2,gbr)"		"\n"
1121	 "0:	mov.<bwl>	%0,r0"		"\n"
1122	 "	<fetchop_name>	%1,r0"		"\n"
1123	 "	mov.<bwl>	r0,%0"		"\n"
1124	 "1:	mov	#0,r0"			"\n"
1125	 "	mov.l	r0,@(%O2,gbr)";
1126}
1127  [(set_attr "length" "18")])
1128
1129;; Combine pattern for xor (val, -1) / nand (val, -1).
1130(define_insn_and_split "atomic_fetch_not<mode>_soft_tcb"
1131  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1132	(match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd"))
1133   (set (match_dup 1)
1134	(unspec:QIHISI [(not:QIHISI (match_dup 1))] UNSPEC_ATOMIC))
1135   (use (match_operand:SI 2 "gbr_displacement"))
1136   (clobber (reg:SI R0_REG))
1137   (clobber (reg:SI R1_REG))]
1138  "TARGET_ATOMIC_SOFT_TCB"
1139{
1140  return "\r	mova	1f,r0"			"\n"
1141	 "	.align 2"			"\n"
1142	 "	mov	#(0f-1f),r1"		"\n"
1143	 "	mov.l	r0,@(%O2,gbr)"		"\n"
1144	 "0:	mov.<bwl>	%1,r0"		"\n"
1145	 "	mov	r0,%0"			"\n"
1146	 "	not	r0,r0"			"\n"
1147	 "	mov.<bwl>	r0,%1"		"\n"
1148	 "1:	mov	#0,r0"			"\n"
1149	 "	mov.l	r0,@(%O2,gbr)";
1150}
1151  "&& can_create_pseudo_p () && optimize
1152   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1153  [(const_int 0)]
1154{
1155  emit_insn (gen_atomic_not<mode>_soft_tcb (operands[1], operands[2]));
1156}
1157  [(set_attr "length" "20")])
1158
1159(define_insn "atomic_not<mode>_soft_tcb"
1160  [(set (match_operand:QIHISI 0 "atomic_mem_operand_1" "=SraSdd")
1161	(unspec:QIHISI [(not:QIHISI (match_dup 0))] UNSPEC_ATOMIC))
1162   (use (match_operand:SI 1 "gbr_displacement"))
1163   (clobber (reg:SI R0_REG))
1164   (clobber (reg:SI R1_REG))]
1165  "TARGET_ATOMIC_SOFT_TCB"
1166{
1167  return "\r	mova	1f,r0"			"\n"
1168	 "	mov	#(0f-1f),r1"		"\n"
1169	 "	.align 2"			"\n"
1170	 "	mov.l	r0,@(%O1,gbr)"		"\n"
1171	 "0:	mov.<bwl>	%0,r0"		"\n"
1172	 "	not	r0,r0"			"\n"
1173	 "	mov.<bwl>	r0,%0"		"\n"
1174	 "1:	mov	#0,r0"			"\n"
1175	 "	mov.l	r0,@(%O1,gbr)";
1176}
1177  [(set_attr "length" "18")])
1178
1179(define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_imask"
1180  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1181	(match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd"))
1182   (set (match_dup 1)
1183	(unspec:QIHISI
1184	  [(FETCHOP:QIHISI
1185		(match_dup 1)
1186		(match_operand:QIHISI 2 "<fetchop_predicate_1>"
1187					"<fetchop_constraint_1_imask>"))]
1188	  UNSPEC_ATOMIC))
1189   (clobber (reg:SI R0_REG))
1190   (clobber (match_scratch:QIHISI 3 "=&r"))]
1191  "TARGET_ATOMIC_SOFT_IMASK"
1192{
1193  return "\r	stc	sr,r0"			"\n"
1194	 "	mov	r0,%3"			"\n"
1195	 "	or	#0xF0,r0"		"\n"
1196	 "	ldc	r0,sr"			"\n"
1197	 "	mov.<bwl>	%1,r0"		"\n"
1198	 "	mov	r0,%0"			"\n"
1199	 "	<fetchop_name>	%2,r0"		"\n"
1200	 "	mov.<bwl>	r0,%1"		"\n"
1201	 "	ldc	%3,sr";
1202}
1203  "&& can_create_pseudo_p () && optimize
1204   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1205  [(const_int 0)]
1206{
1207  emit_insn (gen_atomic_<fetchop_name>_fetch<mode>_soft_imask (
1208			gen_reg_rtx (<MODE>mode), operands[1], operands[2]));
1209}
1210  [(set_attr "length" "18")])
1211
1212;; Combine pattern for xor (val, -1) / nand (val, -1).
1213(define_insn_and_split "atomic_fetch_not<mode>_soft_imask"
1214  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1215	(match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd"))
1216   (set (match_dup 1)
1217	(unspec:QIHISI [(not:QIHISI (match_dup 1))] UNSPEC_ATOMIC))
1218   (clobber (reg:SI R0_REG))
1219   (clobber (match_scratch:QIHISI 2 "=&r"))]
1220  "TARGET_ATOMIC_SOFT_IMASK"
1221{
1222  return "\r	stc	sr,r0"			"\n"
1223	 "	mov	r0,%2"			"\n"
1224	 "	or	#0xF0,r0"		"\n"
1225	 "	ldc	r0,sr"			"\n"
1226	 "	mov.<bwl>	%1,r0"		"\n"
1227	 "	mov	r0,%0"			"\n"
1228	 "	not	r0,r0"			"\n"
1229	 "	mov.<bwl>	r0,%1"		"\n"
1230	 "	ldc	%2,sr";
1231}
1232  "&& can_create_pseudo_p () && optimize
1233   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1234  [(const_int 0)]
1235{
1236  emit_insn (gen_atomic_not_fetch<mode>_soft_imask (gen_reg_rtx (<MODE>mode),
1237						    operands[1]));
1238}
1239  [(set_attr "length" "18")])
1240
1241(define_expand "atomic_fetch_nand<mode>"
1242  [(set (match_operand:QIHISI 0 "arith_reg_dest")
1243	(match_operand:QIHISI 1 "atomic_mem_operand_1"))
1244   (set (match_dup 1)
1245	(unspec:QIHISI
1246	  [(not:QIHISI (and:QIHISI (match_dup 1)
1247		       (match_operand:QIHISI 2 "atomic_logical_operand_1")))]
1248	  UNSPEC_ATOMIC))
1249   (match_operand:SI 3 "const_int_operand")]
1250  "TARGET_ATOMIC_ANY"
1251{
1252  rtx mem = operands[1];
1253  rtx atomic_insn;
1254
1255  if (TARGET_ATOMIC_HARD_LLCS
1256      || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
1257    atomic_insn = gen_atomic_fetch_nand<mode>_hard (operands[0], mem,
1258						    operands[2]);
1259  else if (TARGET_ATOMIC_SOFT_GUSA)
1260    atomic_insn = gen_atomic_fetch_nand<mode>_soft_gusa (operands[0], mem,
1261							 operands[2]);
1262  else if (TARGET_ATOMIC_SOFT_TCB)
1263    atomic_insn = gen_atomic_fetch_nand<mode>_soft_tcb (operands[0], mem,
1264		      operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
1265  else if (TARGET_ATOMIC_SOFT_IMASK)
1266    atomic_insn = gen_atomic_fetch_nand<mode>_soft_imask (operands[0], mem,
1267							  operands[2]);
1268  else
1269    FAIL;
1270
1271  emit_insn (atomic_insn);
1272
1273  if (<MODE>mode == QImode)
1274    emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
1275				     operands[0]));
1276  else if (<MODE>mode == HImode)
1277    emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
1278				     operands[0]));
1279  DONE;
1280})
1281
1282(define_insn_and_split "atomic_fetch_nandsi_hard"
1283  [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
1284	(match_operand:SI 1 "atomic_mem_operand_1" "=Sra"))
1285   (set (match_dup 1)
1286	(unspec:SI
1287	  [(not:SI (and:SI (match_dup 1)
1288		   (match_operand:SI 2 "logical_operand" "rK08")))]
1289	  UNSPEC_ATOMIC))
1290   (set (reg:SI T_REG) (const_int 1))
1291   (clobber (reg:SI R0_REG))]
1292  "TARGET_ATOMIC_HARD_LLCS
1293   || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1294{
1295  return "\r0:	movli.l	%1,r0"		"\n"
1296	 "	mov	r0,%0"		"\n"
1297	 "	and	%2,r0"		"\n"
1298	 "	not	r0,r0"		"\n"
1299	 "	movco.l	r0,%1"		"\n"
1300	 "	bf	0b";
1301}
1302  "&& can_create_pseudo_p () && optimize
1303   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1304  [(const_int 0)]
1305{
1306  emit_insn (gen_atomic_nand_fetchsi_hard (gen_reg_rtx (SImode), operands[1],
1307					   operands[2]));
1308}
1309  [(set_attr "length" "12")])
1310
1311;; The QIHImode llcs patterns modify the address register of the memory
1312;; operand.  In order to express that, we have to open code the memory
1313;; operand.  Initially the insn is expanded like every other atomic insn
1314;; using the memory operand.  In split1 the insn is converted and the
1315;; memory operand's address register is exposed.
1316(define_insn_and_split "atomic_fetch_nand<mode>_hard"
1317  [(set (match_operand:QIHI 0 "arith_reg_dest")
1318	(match_operand:QIHI 1 "atomic_mem_operand_1"))
1319   (set (match_dup 1)
1320	(unspec:QIHI
1321	  [(not:QIHI (and:QIHI (match_dup 1)
1322		     (match_operand:QIHI 2 "logical_operand" "rK08")))]
1323	  UNSPEC_ATOMIC))
1324   (set (reg:SI T_REG) (const_int 1))
1325   (clobber (reg:SI R0_REG))]
1326  "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
1327  "#"
1328  "&& 1"
1329  [(const_int 0)]
1330{
1331  if (optimize
1332      && sh_reg_dead_or_unused_after_insn (curr_insn, REGNO (operands[0])))
1333    emit_insn (gen_atomic_nand<mode>_hard (operands[1], operands[2]));
1334  else
1335    {
1336      rtx i = gen_atomic_fetch_nand<mode>_hard_1 (
1337			operands[0], XEXP (operands[1], 0), operands[2]);
1338
1339      /* Replace the new mems in the new insn with the old mem to preserve
1340	 aliasing info.  */
1341      XEXP (XVECEXP (i, 0, 0), 1) = operands[1];
1342      XEXP (XVECEXP (i, 0, 1), 0) = operands[1];
1343      XEXP (XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 1), 1), 0, 0), 0),
1344	    0) = operands[1];
1345      emit_insn (i);
1346    }
1347})
1348
1349(define_insn "atomic_fetch_nand<mode>_hard_1"
1350  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1351	(mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
1352   (set (mem:QIHI (match_dup 1))
1353	(unspec:QIHI
1354	  [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1))
1355		     (match_operand:QIHI 2 "logical_operand" "rK08")))]
1356	  UNSPEC_ATOMIC))
1357   (set (reg:SI T_REG) (const_int 1))
1358   (clobber (reg:SI R0_REG))
1359   (clobber (match_scratch:SI 3 "=&r"))
1360   (clobber (match_scratch:SI 4 "=1"))]
1361  "TARGET_ATOMIC_HARD_LLCS"
1362{
1363  return "\r	mov	#-4,%3"			"\n"
1364	 "	and	%1,%3"			"\n"
1365	 "	xor	%3,%1"			"\n"
1366	 "	add	r15,%1"			"\n"
1367	 "	add	#-4,%1"			"\n"
1368	 "0:	movli.l	@%3,r0"			"\n"
1369	 "	mov.l	r0,@-r15"		"\n"
1370	 "	mov.<bw>	@%1,r0"		"\n"
1371	 "	mov	r0,%0"			"\n"
1372	 "	and	%2,r0"			"\n"
1373	 "	not	r0,r0"			"\n"
1374	 "	mov.<bw>	r0,@%1"		"\n"
1375	 "	mov.l	@r15+,r0"		"\n"
1376	 "	movco.l	r0,@%3"			"\n"
1377	 "	bf	0b";
1378}
1379  [(set_attr "length" "30")])
1380
1381;; The QIHImode llcs patterns modify the address register of the memory
1382;; operand.  In order to express that, we have to open code the memory
1383;; operand.  Initially the insn is expanded like every other atomic insn
1384;; using the memory operand.  In split1 the insn is converted and the
1385;; memory operand's address register is exposed.
1386(define_insn_and_split "atomic_nand<mode>_hard"
1387  [(set (match_operand:QIHI 0 "atomic_mem_operand_1")
1388	(unspec:QIHI
1389	  [(not:QIHI (and:QIHI (match_dup 0)
1390			       (match_operand:QIHI 1 "logical_operand")))]
1391	  UNSPEC_ATOMIC))
1392   (set (reg:SI T_REG) (const_int 1))
1393   (clobber (reg:SI R0_REG))]
1394  "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
1395  "#"
1396  "&& 1"
1397  [(const_int 0)]
1398{
1399  rtx i = gen_atomic_nand<mode>_hard_1 (XEXP (operands[0], 0), operands[1]);
1400
1401  /* Replace the new mems in the new insn with the old mem to preserve
1402     aliasing info.  */
1403  XEXP (XVECEXP (i, 0, 0), 0) = operands[0];
1404  XEXP (XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 0), 1), 0, 0), 0), 0) = operands[0];
1405  emit_insn (i);
1406})
1407
1408(define_insn "atomic_nand<mode>_hard_1"
1409  [(set (mem:QIHI (match_operand:SI 0 "arith_reg_operand" "r"))
1410	(unspec:QIHI
1411	  [(not:QIHI (and:QIHI (mem:QIHI (match_dup 0))
1412		     (match_operand:QIHI 1 "logical_operand" "rK08")))]
1413	  UNSPEC_ATOMIC))
1414   (set (reg:SI T_REG) (const_int 1))
1415   (clobber (reg:SI R0_REG))
1416   (clobber (match_scratch:SI 2 "=&r"))
1417   (clobber (match_scratch:SI 3 "=0"))]
1418  "TARGET_ATOMIC_HARD_LLCS"
1419{
1420  return "\r	mov	#-4,%2"			"\n"
1421	 "	and	%0,%2"			"\n"
1422	 "	xor	%2,%0"			"\n"
1423	 "	add	r15,%0"			"\n"
1424	 "	add	#-4,%0"			"\n"
1425	 "0:	movli.l	@%2,r0"			"\n"
1426	 "	mov.l	r0,@-r15"		"\n"
1427	 "	mov.<bw>	@%0,r0"		"\n"
1428	 "	and	%1,r0"			"\n"
1429	 "	not	r0,r0"			"\n"
1430	 "	mov.<bw>	r0,@%0"		"\n"
1431	 "	mov.l	@r15+,r0"		"\n"
1432	 "	movco.l	r0,@%2"			"\n"
1433	 "	bf	0b";
1434}
1435  [(set_attr "length" "28")])
1436
1437(define_insn_and_split "atomic_fetch_nand<mode>_soft_gusa"
1438  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1439	(match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd"))
1440   (set (match_dup 1)
1441	(unspec:QIHISI
1442	  [(not:QIHISI
1443	     (and:QIHISI (match_dup 1)
1444			 (match_operand:QIHISI 2 "arith_reg_operand" "u")))]
1445	  UNSPEC_ATOMIC))
1446   (clobber (match_scratch:QIHISI 3 "=&u"))
1447   (clobber (reg:SI R0_REG))
1448   (clobber (reg:SI R1_REG))]
1449  "TARGET_ATOMIC_SOFT_GUSA"
1450{
1451  return "\r	mova	1f,r0"			"\n"
1452	 "	mov	r15,r1"			"\n"
1453	 "	.align 2"			"\n"
1454	 "	mov	#(0f-1f),r15"		"\n"
1455	 "0:	mov.<bwl>	%1,%0"		"\n"
1456	 "	mov	%2,%3"			"\n"
1457	 "	and	%0,%3"			"\n"
1458	 "	not	%3,%3"			"\n"
1459	 "	mov.<bwl>	%3,%1"		"\n"
1460	 "1:	mov	r1,r15";
1461}
1462  "&& can_create_pseudo_p () && optimize
1463   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1464  [(const_int 0)]
1465{
1466  emit_insn (gen_atomic_nand_fetch<mode>_soft_gusa (gen_reg_rtx (<MODE>mode),
1467						    operands[1], operands[2]));
1468}
1469  [(set_attr "length" "20")])
1470
1471(define_insn_and_split "atomic_fetch_nand<mode>_soft_tcb"
1472  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1473	(match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd"))
1474   (set (match_dup 1)
1475	(unspec:QIHISI
1476	  [(not:QIHISI
1477	     (and:QIHISI (match_dup 1)
1478			 (match_operand:QIHISI 2 "logical_operand" "rK08")))]
1479	  UNSPEC_ATOMIC))
1480   (use (match_operand:SI 3 "gbr_displacement"))
1481   (clobber (reg:SI R0_REG))
1482   (clobber (reg:SI R1_REG))]
1483  "TARGET_ATOMIC_SOFT_TCB"
1484{
1485  return "\r	mova	1f,r0"			"\n"
1486	 "	mov	#(0f-1f),r1"		"\n"
1487	 "	.align 2"			"\n"
1488	 "	mov.l	r0,@(%O3,gbr)"		"\n"
1489	 "0:	mov.<bwl>	%1,r0"		"\n"
1490	 "	mov	r0,%0"			"\n"
1491	 "	and	%2,r0"			"\n"
1492	 "	not	r0,r0"			"\n"
1493	 "	mov.<bwl>	r0,%1"		"\n"
1494	 "1:	mov	#0,r0"			"\n"
1495	 "	mov.l	r0,@(%O3,gbr)";
1496}
1497  "&& can_create_pseudo_p () && optimize
1498   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1499  [(const_int 0)]
1500{
1501  emit_insn (gen_atomic_nand<mode>_soft_tcb (operands[1], operands[2],
1502					     operands[3]));
1503}
1504  [(set_attr "length" "22")])
1505
1506(define_insn "atomic_nand<mode>_soft_tcb"
1507  [(set (match_operand:QIHISI 0 "atomic_mem_operand_1" "=SraSdd")
1508	(unspec:QIHISI
1509	  [(not:QIHISI
1510	     (and:QIHISI (match_dup 0)
1511			 (match_operand:QIHISI 1 "logical_operand" "rK08")))]
1512	  UNSPEC_ATOMIC))
1513   (use (match_operand:SI 2 "gbr_displacement"))
1514   (clobber (reg:SI R0_REG))
1515   (clobber (reg:SI R1_REG))]
1516  "TARGET_ATOMIC_SOFT_TCB"
1517{
1518  return "\r	mova	1f,r0"			"\n"
1519	 "	.align 2"			"\n"
1520	 "	mov	#(0f-1f),r1"		"\n"
1521	 "	mov.l	r0,@(%O2,gbr)"		"\n"
1522	 "0:	mov.<bwl>	%0,r0"		"\n"
1523	 "	and	%1,r0"			"\n"
1524	 "	not	r0,r0"			"\n"
1525	 "	mov.<bwl>	r0,%0"		"\n"
1526	 "1:	mov	#0,r0"			"\n"
1527	 "	mov.l	r0,@(%O2,gbr)";
1528}
1529  [(set_attr "length" "20")])
1530
1531(define_insn_and_split "atomic_fetch_nand<mode>_soft_imask"
1532  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1533	(match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd"))
1534   (set (match_dup 1)
1535	(unspec:QIHISI
1536	  [(not:QIHISI
1537	     (and:QIHISI (match_dup 1)
1538			 (match_operand:QIHISI 2 "logical_operand" "rK08")))]
1539	  UNSPEC_ATOMIC))
1540   (clobber (reg:SI R0_REG))
1541   (clobber (match_scratch:SI 3 "=&r"))]
1542  "TARGET_ATOMIC_SOFT_IMASK"
1543{
1544  return "\r	stc	sr,r0"			"\n"
1545	 "	mov	r0,%3"			"\n"
1546	 "	or	#0xF0,r0"		"\n"
1547	 "	ldc	r0,sr"			"\n"
1548	 "	mov.<bwl>	%1,r0"		"\n"
1549	 "	mov	r0,%0"			"\n"
1550	 "	and	%2,r0"			"\n"
1551	 "	not	r0,r0"			"\n"
1552	 "	mov.<bwl>	r0,%1"		"\n"
1553	 "	ldc	%3,sr";
1554}
1555  "&& can_create_pseudo_p () && optimize
1556   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1557  [(const_int 0)]
1558{
1559  emit_insn (gen_atomic_nand_fetch<mode>_soft_imask (gen_reg_rtx (<MODE>mode),
1560						     operands[1], operands[2]));
1561}
1562  [(set_attr "length" "20")])
1563
1564;;------------------------------------------------------------------------------
1565;; read - add|sub|or|and|xor|nand - write - return new value
1566
1567(define_expand "atomic_<fetchop_name>_fetch<mode>"
1568  [(set (match_operand:QIHISI 0 "arith_reg_dest")
1569	(FETCHOP:QIHISI
1570	  (match_operand:QIHISI 1 "atomic_mem_operand_1")
1571	  (match_operand:QIHISI 2 "<fetchop_predicate_1>")))
1572   (set (match_dup 1)
1573	(unspec:QIHISI
1574	  [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))]
1575	  UNSPEC_ATOMIC))
1576   (match_operand:SI 3 "const_int_operand" "")]
1577  "TARGET_ATOMIC_ANY"
1578{
1579  rtx mem = operands[1];
1580  rtx atomic_insn;
1581
1582  if (TARGET_ATOMIC_HARD_LLCS
1583      || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
1584    atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_hard (operands[0], mem,
1585							      operands[2]);
1586  else if (TARGET_ATOMIC_SOFT_GUSA)
1587    atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_gusa (operands[0],
1588		      mem, operands[2]);
1589  else if (TARGET_ATOMIC_SOFT_TCB)
1590    atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_tcb (operands[0],
1591		      mem, operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
1592  else if (TARGET_ATOMIC_SOFT_IMASK)
1593    atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_imask (operands[0],
1594		      mem, operands[2]);
1595  else
1596    FAIL;
1597
1598  emit_insn (atomic_insn);
1599
1600  if (<MODE>mode == QImode)
1601    emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
1602				     operands[0]));
1603  else if (<MODE>mode == HImode)
1604    emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
1605				     operands[0]));
1606  DONE;
1607})
1608
1609(define_insn "atomic_<fetchop_name>_fetchsi_hard"
1610  [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
1611	(FETCHOP:SI
1612	  (match_operand:SI 1 "atomic_mem_operand_1" "=Sra")
1613	  (match_operand:SI 2 "<fetchop_predicate_1>"
1614			      "<fetchop_constraint_1_llcs>")))
1615   (set (match_dup 1)
1616	(unspec:SI
1617	  [(FETCHOP:SI (match_dup 1) (match_dup 2))]
1618	  UNSPEC_ATOMIC))
1619   (set (reg:SI T_REG) (const_int 1))]
1620  "TARGET_ATOMIC_HARD_LLCS
1621   || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1622{
1623  return "\r0:	movli.l	%1,%0"		"\n"
1624	 "	<fetchop_name>	%2,%0"	"\n"
1625	 "	movco.l	%0,%1"		"\n"
1626	 "	bf	0b";
1627}
1628  [(set_attr "length" "8")])
1629
1630;; Combine pattern for xor (val, -1) / nand (val, -1).
1631(define_insn "atomic_not_fetchsi_hard"
1632  [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
1633	(not:SI (match_operand:SI 1 "atomic_mem_operand_1" "=Sra")))
1634   (set (match_dup 1)
1635	(unspec:SI [(not:SI (match_dup 1))] UNSPEC_ATOMIC))
1636   (set (reg:SI T_REG) (const_int 1))]
1637  "TARGET_ATOMIC_HARD_LLCS
1638   || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1639{
1640  return "\r0:	movli.l	%1,%0"		"\n"
1641	 "	not	%0,%0"		"\n"
1642	 "	movco.l	%0,%1"		"\n"
1643	 "	bf	0b";
1644}
1645  [(set_attr "length" "8")])
1646
1647;; The QIHImode llcs patterns modify the address register of the memory
1648;; operand.  In order to express that, we have to open code the memory
1649;; operand.  Initially the insn is expanded like every other atomic insn
1650;; using the memory operand.  In split1 the insn is converted and the
1651;; memory operand's address register is exposed.
1652(define_insn_and_split "atomic_<fetchop_name>_fetch<mode>_hard"
1653  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1654	(FETCHOP:QIHI (match_operand:QIHI 1 "atomic_mem_operand_1")
1655		      (match_operand:QIHI 2 "<fetchop_predicate_1>")))
1656   (set (match_dup 1) (unspec:QIHI [(FETCHOP:QIHI (match_dup 1) (match_dup 2))]
1657				   UNSPEC_ATOMIC))
1658   (set (reg:SI T_REG) (const_int 1))
1659   (clobber (reg:SI R0_REG))]
1660  "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
1661  "#"
1662  "&& 1"
1663  [(const_int 0)]
1664{
1665  if (optimize
1666      && sh_reg_dead_or_unused_after_insn (curr_insn, REGNO (operands[0])))
1667    emit_insn (gen_atomic_<fetchop_name><mode>_hard (operands[1], operands[2]));
1668  else
1669    {
1670      rtx i = gen_atomic_<fetchop_name>_fetch<mode>_hard_1 (
1671			operands[0], XEXP (operands[1], 0), operands[2]);
1672
1673      /* Replace the new mems in the new insn with the old mem to preserve
1674	 aliasing info.  */
1675      XEXP (XEXP (XVECEXP (i, 0, 0), 1), 0) = operands[1];
1676      XEXP (XVECEXP (i, 0, 1), 0) = operands[1];
1677      XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 1), 1), 0, 0), 0) = operands[1];
1678      emit_insn (i);
1679    }
1680})
1681
1682(define_insn "atomic_<fetchop_name>_fetch<mode>_hard_1"
1683  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1684	(FETCHOP:QIHI
1685	  (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
1686	  (match_operand:QIHI 2 "<fetchop_predicate_1>"
1687				"<fetchop_constraint_1_llcs>")))
1688   (set (mem:QIHI (match_dup 1))
1689	(unspec:QIHI
1690	  [(FETCHOP:QIHI (mem:QIHI (match_dup 1)) (match_dup 2))]
1691	  UNSPEC_ATOMIC))
1692   (set (reg:SI T_REG) (const_int 1))
1693   (clobber (reg:SI R0_REG))
1694   (clobber (match_scratch:SI 3 "=&r"))
1695   (clobber (match_scratch:SI 4 "=1"))]
1696  "TARGET_ATOMIC_HARD_LLCS"
1697{
1698  return "\r	mov	#-4,%3"			"\n"
1699	 "	and	%1,%3"			"\n"
1700	 "	xor	%3,%1"			"\n"
1701	 "	add	r15,%1"			"\n"
1702	 "	add	#-4,%1"			"\n"
1703	 "0:	movli.l	@%3,r0"			"\n"
1704	 "	mov.l	r0,@-r15"		"\n"
1705	 "	mov.<bw>	@%1,r0"		"\n"
1706	 "	<fetchop_name>	%2,r0"		"\n"
1707	 "	mov.<bw>	r0,@%1"		"\n"
1708	 "	mov	r0,%0"			"\n"
1709	 "	mov.l	@r15+,r0"		"\n"
1710	 "	movco.l	r0,@%3"			"\n"
1711	 "	bf	0b";
1712}
1713  [(set_attr "length" "28")])
1714
1715;; Combine pattern for xor (val, -1) / nand (val, -1).
1716(define_insn_and_split "atomic_not_fetch<mode>_hard"
1717  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1718	(not:QIHI (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))))
1719   (set (mem:QIHI (match_dup 1))
1720	(unspec:QIHI [(not:QIHI (mem:QIHI (match_dup 1)))] UNSPEC_ATOMIC))
1721   (set (reg:SI T_REG) (const_int 1))
1722   (clobber (reg:SI R0_REG))
1723   (clobber (match_scratch:SI 2 "=&r"))
1724   (clobber (match_scratch:SI 3 "=1"))]
1725  "TARGET_ATOMIC_HARD_LLCS"
1726{
1727  return "\r	mov	#-4,%2"			"\n"
1728	 "	and	%1,%2"			"\n"
1729	 "	xor	%2,%1"			"\n"
1730	 "	add	r15,%1"			"\n"
1731	 "	add	#-4,%1"			"\n"
1732	 "0:	movli.l	@%2,r0"			"\n"
1733	 "	mov.l	r0,@-r15"		"\n"
1734	 "	mov.<bw>	@%1,r0"		"\n"
1735	 "	not	r0,r0"			"\n"
1736	 "	mov.<bw>	r0,@%1"		"\n"
1737	 "	mov	r0,%0"			"\n"
1738	 "	mov.l	@r15+,r0"		"\n"
1739	 "	movco.l	r0,@%2"			"\n"
1740	 "	bf	0b";
1741}
1742  "&& can_create_pseudo_p () && optimize
1743   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1744  [(const_int 0)]
1745{
1746  rtx i = gen_atomic_not<mode>_hard (operands[1]);
1747
1748  /* Replace the new mems in the new insn with the old mem to preserve
1749     aliasing info.  */
1750  rtx m = XEXP (XEXP (XVECEXP (PATTERN (curr_insn), 0, 0), 1), 0);
1751  XEXP (XVECEXP (i, 0, 0), 0) = m;
1752  XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 0), 1), 0, 0), 0) = m;
1753  emit_insn (i);
1754}
1755  [(set_attr "length" "28")])
1756
1757(define_insn "atomic_<fetchop_name>_fetch<mode>_soft_gusa"
1758  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1759	(FETCHOP:QIHISI
1760	  (match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd")
1761	  (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1762				  "<fetchop_constraint_1_gusa>")))
1763   (set (match_dup 1)
1764	(unspec:QIHISI
1765	  [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))]
1766	  UNSPEC_ATOMIC))
1767   (clobber (reg:SI R0_REG))
1768   (clobber (reg:SI R1_REG))]
1769  "TARGET_ATOMIC_SOFT_GUSA"
1770{
1771  return "\r	mova	1f,r0"			"\n"
1772	 "	mov	r15,r1"			"\n"
1773	 "	.align 2"			"\n"
1774	 "	mov	#(0f-1f),r15"		"\n"
1775	 "0:	mov.<bwl>	%1,%0"		"\n"
1776	 "	<fetchop_name>	%2,%0"		"\n"
1777	 "	mov.<bwl>	%0,%1"		"\n"
1778	 "1:	mov	r1,r15";
1779}
1780  [(set_attr "length" "16")])
1781
1782;; Combine pattern for xor (val, -1) / nand (val, -1).
1783(define_insn "atomic_not_fetch<mode>_soft_gusa"
1784  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1785	(not:QIHISI (match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd")))
1786   (set (match_dup 1)
1787	(unspec:QIHISI [(not:QIHISI (match_dup 1))] UNSPEC_ATOMIC))
1788   (clobber (reg:SI R0_REG))
1789   (clobber (reg:SI R1_REG))]
1790  "TARGET_ATOMIC_SOFT_GUSA"
1791{
1792  return "\r	mova	1f,r0"			"\n"
1793	 "	mov	r15,r1"			"\n"
1794	 "	.align 2"			"\n"
1795	 "	mov	#(0f-1f),r15"		"\n"
1796	 "0:	mov.<bwl>	%1,%0"		"\n"
1797	 "	not	%0,%0"			"\n"
1798	 "	mov.<bwl>	%0,%1"		"\n"
1799	 "1:	mov	r1,r15";
1800}
1801  [(set_attr "length" "16")])
1802
1803(define_insn_and_split "atomic_<fetchop_name>_fetch<mode>_soft_tcb"
1804  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1805	(FETCHOP:QIHISI
1806	  (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")
1807	  (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1808				  "<fetchop_constraint_1_tcb>")))
1809   (set (match_dup 1)
1810	(unspec:QIHISI
1811	  [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))]
1812	  UNSPEC_ATOMIC))
1813   (clobber (reg:SI R0_REG))
1814   (clobber (reg:SI R1_REG))
1815   (use (match_operand:SI 3 "gbr_displacement"))]
1816  "TARGET_ATOMIC_SOFT_TCB"
1817{
1818  return "\r	mova	1f,r0"			"\n"
1819	 "	mov	#(0f-1f),r1"		"\n"
1820	 "	.align 2"			"\n"
1821	 "	mov.l	r0,@(%O3,gbr)"		"\n"
1822	 "0:	mov.<bwl>	%1,r0"		"\n"
1823	 "	<fetchop_name>	%2,r0"		"\n"
1824	 "	mov.<bwl>	r0,%1"		"\n"
1825	 "1:	mov	r0,%0"			"\n"
1826	 "	mov	#0,r0"			"\n"
1827	 "	mov.l	r0,@(%O3,gbr)";
1828}
1829  "&& can_create_pseudo_p () && optimize
1830   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1831  [(const_int 0)]
1832{
1833  emit_insn (gen_atomic_<fetchop_name><mode>_soft_tcb (
1834				operands[1], operands[2], operands[3]));
1835}
1836  [(set_attr "length" "20")])
1837
1838;; Combine pattern for xor (val, -1) / nand (val, -1).
1839(define_insn_and_split "atomic_not_fetch<mode>_soft_tcb"
1840  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1841	(not:QIHISI (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")))
1842   (set (match_dup 1)
1843	(unspec:QIHISI [(not:QIHISI (match_dup 1))] UNSPEC_ATOMIC))
1844   (clobber (reg:SI R0_REG))
1845   (clobber (reg:SI R1_REG))
1846   (use (match_operand:SI 2 "gbr_displacement"))]
1847  "TARGET_ATOMIC_SOFT_TCB"
1848{
1849  return "\r	mova	1f,r0"			"\n"
1850	 "	mov	#(0f-1f),r1"		"\n"
1851	 "	.align 2"			"\n"
1852	 "	mov.l	r0,@(%O2,gbr)"		"\n"
1853	 "0:	mov.<bwl>	%1,r0"		"\n"
1854	 "	not	r0,r0"			"\n"
1855	 "	mov.<bwl>	r0,%1"		"\n"
1856	 "1:	mov	r0,%0"			"\n"
1857	 "	mov	#0,r0"			"\n"
1858	 "	mov.l	r0,@(%O2,gbr)";
1859}
1860  "&& can_create_pseudo_p () && optimize
1861   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1862  [(const_int 0)]
1863{
1864  emit_insn (gen_atomic_not<mode>_soft_tcb (operands[1], operands[2]));
1865}
1866  [(set_attr "length" "20")])
1867
1868(define_insn "atomic_<fetchop_name>_fetch<mode>_soft_imask"
1869  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
1870	(FETCHOP:QIHISI
1871	  (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")
1872	  (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1873				  "<fetchop_constraint_1_imask>")))
1874   (set (match_dup 1)
1875	(unspec:QIHISI
1876	  [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))]
1877	  UNSPEC_ATOMIC))
1878   (clobber (match_scratch:SI 3 "=&r"))]
1879  "TARGET_ATOMIC_SOFT_IMASK"
1880{
1881  return "\r	stc	sr,%0"			"\n"
1882	 "	mov	%0,%3"			"\n"
1883	 "	or	#0xF0,%0"		"\n"
1884	 "	ldc	%0,sr"			"\n"
1885	 "	mov.<bwl>	%1,%0"		"\n"
1886	 "	<fetchop_name>	%2,%0"		"\n"
1887	 "	mov.<bwl>	%0,%1"		"\n"
1888	 "	ldc	%3,sr";
1889}
1890  [(set_attr "length" "16")])
1891
1892;; Combine pattern for xor (val, -1) / nand (val, -1).
1893(define_insn "atomic_not_fetch<mode>_soft_imask"
1894  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
1895	(not:QIHISI (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")))
1896   (set (match_dup 1)
1897	(unspec:QIHISI [(not:QIHISI (match_dup 1))] UNSPEC_ATOMIC))
1898   (clobber (match_scratch:SI 2 "=&r"))]
1899  "TARGET_ATOMIC_SOFT_IMASK"
1900{
1901  return "\r	stc	sr,%0"			"\n"
1902	 "	mov	%0,%2"			"\n"
1903	 "	or	#0xF0,%0"		"\n"
1904	 "	ldc	%0,sr"			"\n"
1905	 "	mov.<bwl>	%1,%0"		"\n"
1906	 "	not	%0,%0"			"\n"
1907	 "	mov.<bwl>	%0,%1"		"\n"
1908	 "	ldc	%2,sr";
1909}
1910  [(set_attr "length" "16")])
1911
1912(define_expand "atomic_nand_fetch<mode>"
1913  [(set (match_operand:QIHISI 0 "arith_reg_dest")
1914	(not:QIHISI (and:QIHISI
1915	  (match_operand:QIHISI 1 "atomic_mem_operand_1")
1916	  (match_operand:QIHISI 2 "atomic_logical_operand_1"))))
1917   (set (match_dup 1)
1918	(unspec:QIHISI
1919	  [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))]
1920	  UNSPEC_ATOMIC))
1921   (match_operand:SI 3 "const_int_operand")]
1922  "TARGET_ATOMIC_ANY"
1923{
1924  rtx mem = operands[1];
1925  rtx atomic_insn;
1926
1927  if (TARGET_ATOMIC_HARD_LLCS
1928      || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
1929    atomic_insn = gen_atomic_nand_fetch<mode>_hard (operands[0], mem,
1930						    operands[2]);
1931  else if (TARGET_ATOMIC_SOFT_GUSA)
1932    atomic_insn = gen_atomic_nand_fetch<mode>_soft_gusa (operands[0], mem,
1933							 operands[2]);
1934  else if (TARGET_ATOMIC_SOFT_TCB)
1935    atomic_insn = gen_atomic_nand_fetch<mode>_soft_tcb (operands[0], mem,
1936		      operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
1937  else if (TARGET_ATOMIC_SOFT_IMASK)
1938    atomic_insn = gen_atomic_nand_fetch<mode>_soft_imask (operands[0], mem,
1939							  operands[2]);
1940  else
1941    FAIL;
1942
1943  emit_insn (atomic_insn);
1944
1945  if (<MODE>mode == QImode)
1946    emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
1947				     operands[0]));
1948  else if (<MODE>mode == HImode)
1949    emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
1950				     operands[0]));
1951  DONE;
1952})
1953
1954(define_insn "atomic_nand_fetchsi_hard"
1955  [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
1956	(not:SI (and:SI (match_operand:SI 1 "atomic_mem_operand_1" "=Sra")
1957			(match_operand:SI 2 "logical_operand" "rK08"))))
1958   (set (match_dup 1)
1959	(unspec:SI
1960	  [(not:SI (and:SI (match_dup 1) (match_dup 2)))]
1961	  UNSPEC_ATOMIC))
1962   (set (reg:SI T_REG) (const_int 1))]
1963  "TARGET_ATOMIC_HARD_LLCS
1964   || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1965{
1966  return "\r0:	movli.l	%1,%0"		"\n"
1967	 "	and	%2,%0"		"\n"
1968	 "	not	%0,%0"		"\n"
1969	 "	movco.l	%0,%1"		"\n"
1970	 "	bf	0b";
1971}
1972  [(set_attr "length" "10")])
1973
1974;; The QIHImode llcs patterns modify the address register of the memory
1975;; operand.  In order to express that, we have to open code the memory
1976;; operand.  Initially the insn is expanded like every other atomic insn
1977;; using the memory operand.  In split1 the insn is converted and the
1978;; memory operand's address register is exposed.
1979(define_insn_and_split "atomic_nand_fetch<mode>_hard"
1980  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1981	(not:QIHI (and:QIHI (match_operand:QIHI 1 "atomic_mem_operand_1")
1982			    (match_operand:QIHI 2 "logical_operand"))))
1983   (set (match_dup 1)
1984	(unspec:QIHI [(not:QIHI (and:QIHI (match_dup 1) (match_dup 2)))]
1985		     UNSPEC_ATOMIC))
1986   (set (reg:SI T_REG) (const_int 1))
1987   (clobber (reg:SI R0_REG))]
1988  "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
1989  "#"
1990  "&& 1"
1991  [(const_int 0)]
1992{
1993  if (optimize
1994      && sh_reg_dead_or_unused_after_insn (curr_insn, REGNO (operands[0])))
1995    emit_insn (gen_atomic_nand<mode>_hard (operands[1], operands[2]));
1996  else
1997    {
1998      rtx i = gen_atomic_nand_fetch<mode>_hard_1 (
1999			operands[0], XEXP (operands[1], 0), operands[2]);
2000
2001      /* Replace the new mems in the new insn with the old mem to preserve
2002	 aliasing info.  */
2003      XEXP (XEXP (XEXP (XVECEXP (i, 0, 0), 1), 0), 0) = operands[1];
2004      XEXP (XVECEXP (i, 0, 1), 0) = operands[1];
2005      XEXP (XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 1), 1), 0, 0), 0),
2006	    0) = operands[1];
2007      emit_insn (i);
2008    }
2009})
2010
2011(define_insn "atomic_nand_fetch<mode>_hard_1"
2012  [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
2013	(not:QIHI
2014	  (and:QIHI (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
2015		    (match_operand:QIHI 2 "logical_operand" "rK08"))))
2016   (set (mem:QIHI (match_dup 1))
2017	(unspec:QIHI
2018	  [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1)) (match_dup 2)))]
2019	  UNSPEC_ATOMIC))
2020   (set (reg:SI T_REG) (const_int 1))
2021   (clobber (reg:SI R0_REG))
2022   (clobber (match_scratch:SI 3 "=&r"))
2023   (clobber (match_scratch:SI 4 "=1"))]
2024  "TARGET_ATOMIC_HARD_LLCS"
2025{
2026  return "\r	mov	#-4,%3"			"\n"
2027	 "	and	%1,%3"			"\n"
2028	 "	xor	%3,%1"			"\n"
2029	 "	add	r15,%1"			"\n"
2030	 "	add	#-4,%1"			"\n"
2031	 "0:	movli.l	@%3,r0"			"\n"
2032	 "	mov.l	r0,@-r15"		"\n"
2033	 "	mov.<bw>	@%1,r0"		"\n"
2034	 "	and	%2,r0"			"\n"
2035	 "	not	r0,%0"			"\n"
2036	 "	mov.<bw>	%0,@%1"		"\n"
2037	 "	mov.l	@r15+,r0"		"\n"
2038	 "	movco.l	r0,@%3"			"\n"
2039	 "	bf	0b";
2040}
2041  [(set_attr "length" "28")])
2042
2043(define_insn "atomic_nand_fetch<mode>_soft_gusa"
2044  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
2045	(not:QIHISI (and:QIHISI
2046	  (match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd")
2047	  (match_operand:QIHISI 2 "arith_reg_operand" "u"))))
2048   (set (match_dup 1)
2049	(unspec:QIHISI
2050	  [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))]
2051	  UNSPEC_ATOMIC))
2052   (clobber (reg:SI R0_REG))
2053   (clobber (reg:SI R1_REG))]
2054  "TARGET_ATOMIC_SOFT_GUSA"
2055{
2056  return "\r	mova	1f,r0"			"\n"
2057	 "	.align 2"			"\n"
2058	 "	mov	r15,r1"			"\n"
2059	 "	mov	#(0f-1f),r15"		"\n"
2060	 "0:	mov.<bwl>	%1,%0"		"\n"
2061	 "	and	%2,%0"			"\n"
2062	 "	not	%0,%0"			"\n"
2063	 "	mov.<bwl>	%0,%1"		"\n"
2064	 "1:	mov	r1,r15";
2065}
2066  [(set_attr "length" "18")])
2067
2068(define_insn_and_split "atomic_nand_fetch<mode>_soft_tcb"
2069  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
2070	(not:QIHISI (and:QIHISI
2071	  (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")
2072	  (match_operand:QIHISI 2 "logical_operand" "rK08"))))
2073   (set (match_dup 1)
2074	(unspec:QIHISI
2075	  [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))]
2076	  UNSPEC_ATOMIC))
2077   (clobber (reg:SI R0_REG))
2078   (clobber (reg:SI R1_REG))
2079   (use (match_operand:SI 3 "gbr_displacement"))]
2080  "TARGET_ATOMIC_SOFT_TCB"
2081{
2082  return "\r	mova	1f,r0"			"\n"
2083	 "	mov	#(0f-1f),r1"		"\n"
2084	 "	.align 2"			"\n"
2085	 "	mov.l	r0,@(%O3,gbr)"		"\n"
2086	 "0:	mov.<bwl>	%1,r0"		"\n"
2087	 "	and	%2,r0"			"\n"
2088	 "	not	r0,r0"			"\n"
2089	 "	mov	r0,%0"			"\n"
2090	 "	mov.<bwl>	r0,%1"		"\n"
2091	 "1:	mov	#0,r0"			"\n"
2092	 "	mov.l	r0,@(%O3,gbr)";
2093}
2094  "&& can_create_pseudo_p () && optimize
2095   && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
2096  [(const_int 0)]
2097{
2098  emit_insn (gen_atomic_nand<mode>_soft_tcb (operands[1], operands[2],
2099					     operands[3]));
2100}
2101  [(set_attr "length" "22")])
2102
2103(define_insn "atomic_nand_fetch<mode>_soft_imask"
2104  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
2105	(not:QIHISI (and:QIHISI
2106	  (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")
2107	  (match_operand:QIHISI 2 "logical_operand" "rK08"))))
2108   (set (match_dup 1)
2109	(unspec:QIHISI
2110	  [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))]
2111	  UNSPEC_ATOMIC))
2112   (clobber (match_scratch:SI 3 "=&r"))]
2113  "TARGET_ATOMIC_SOFT_IMASK"
2114{
2115  return "\r	stc	sr,%0"			"\n"
2116	 "	mov	%0,%3"			"\n"
2117	 "	or	#0xF0,%0"		"\n"
2118	 "	ldc	%0,sr"			"\n"
2119	 "	mov.<bwl>	%1,%0"		"\n"
2120	 "	and	%2,%0"			"\n"
2121	 "	not	%0,%0"			"\n"
2122	 "	mov.<bwl>	%0,%1"		"\n"
2123	 "	ldc	%3,sr";
2124}
2125  [(set_attr "length" "18")])
2126
2127;;------------------------------------------------------------------------------
2128;; read - test against zero - or with 0x80 - write - return test result
2129
2130(define_expand "atomic_test_and_set"
2131  [(match_operand:SI 0 "register_operand" "")		;; bool result output
2132   (match_operand:QI 1 "memory_operand" "")		;; memory
2133   (match_operand:SI 2 "const_int_operand" "")]		;; model
2134  "TARGET_ATOMIC_ANY || TARGET_ENABLE_TAS"
2135{
2136  rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
2137
2138  if (TARGET_ENABLE_TAS)
2139    emit_insn (gen_tasb (addr));
2140  else
2141    {
2142      rtx val = gen_int_mode (targetm.atomic_test_and_set_trueval, QImode);
2143      val = force_reg (QImode, val);
2144
2145      if (TARGET_ATOMIC_HARD_LLCS)
2146	  emit_insn (gen_atomic_test_and_set_hard (addr, val));
2147      else if (TARGET_ATOMIC_SOFT_GUSA)
2148	  emit_insn (gen_atomic_test_and_set_soft_gusa (addr, val));
2149      else if (TARGET_ATOMIC_SOFT_TCB)
2150	  emit_insn (gen_atomic_test_and_set_soft_tcb (addr, val,
2151			 TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX));
2152      else if (TARGET_ATOMIC_SOFT_IMASK)
2153	  emit_insn (gen_atomic_test_and_set_soft_imask (addr, val));
2154      else
2155	FAIL;
2156    }
2157
2158  /* The result of the test op is the inverse of what we are
2159     supposed to return.  Thus invert the T bit.  The inversion will be
2160     potentially optimized away and integrated into surrounding code.  */
2161  emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ()));
2162  DONE;
2163})
2164
2165(define_insn "tasb"
2166  [(set (reg:SI T_REG)
2167	(eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
2168	       (const_int 0)))
2169   (set (mem:QI (match_dup 0))
2170	(unspec:QI [(const_int 128)] UNSPEC_ATOMIC))]
2171  "TARGET_ENABLE_TAS"
2172  "tas.b	@%0"
2173  [(set_attr "insn_class" "co_group")])
2174
2175(define_insn "atomic_test_and_set_soft_gusa"
2176  [(set (reg:SI T_REG)
2177	(eq:SI (mem:QI (match_operand:SI 0 "register_operand" "u"))
2178	       (const_int 0)))
2179   (set (mem:QI (match_dup 0))
2180	(unspec:QI [(match_operand:QI 1 "register_operand" "u")] UNSPEC_ATOMIC))
2181   (clobber (match_scratch:QI 2 "=&u"))
2182   (clobber (reg:SI R0_REG))
2183   (clobber (reg:SI R1_REG))]
2184  "TARGET_ATOMIC_SOFT_GUSA && !TARGET_ENABLE_TAS"
2185{
2186  return "\r	mova	1f,r0"		"\n"
2187	 "	.align 2"		"\n"
2188	 "	mov	r15,r1"		"\n"
2189	 "	mov	#(0f-1f),r15"	"\n"
2190	 "0:	mov.b	@%0,%2"		"\n"
2191	 "	mov.b	%1,@%0"		"\n"
2192	 "1:	mov	r1,r15"		"\n"
2193	 "	tst	%2,%2";
2194}
2195  [(set_attr "length" "16")])
2196
2197(define_insn "atomic_test_and_set_soft_tcb"
2198  [(set (reg:SI T_REG)
2199	(eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
2200	       (const_int 0)))
2201   (set (mem:QI (match_dup 0))
2202	(unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
2203   (use (match_operand:SI 2 "gbr_displacement"))
2204   (clobber (match_scratch:QI 3 "=&r"))
2205   (clobber (reg:SI R0_REG))
2206   (clobber (reg:SI R1_REG))]
2207  "TARGET_ATOMIC_SOFT_TCB && !TARGET_ENABLE_TAS"
2208{
2209  return "\r	mova	1f,r0"		"\n"
2210	 "	mov	#(0f-1f),r1"	"\n"
2211	 "	.align 2"		"\n"
2212	 "	mov.l	r0,@(%O2,gbr)"	"\n"
2213	 "0:	mov.b	@%0,%3"		"\n"
2214	 "	mov	#0,r0"		"\n"
2215	 "	mov.b	%1,@%0"		"\n"
2216	 "1:	mov.l	r0,@(%O2,gbr)"	"\n"
2217	 "	tst	%3,%3";
2218}
2219  [(set_attr "length" "18")])
2220
2221(define_insn "atomic_test_and_set_soft_imask"
2222  [(set (reg:SI T_REG)
2223	(eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
2224	       (const_int 0)))
2225   (set (mem:QI (match_dup 0))
2226	(unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
2227   (clobber (match_scratch:SI 2 "=&r"))
2228   (clobber (reg:SI R0_REG))]
2229  "TARGET_ATOMIC_SOFT_IMASK && !TARGET_ENABLE_TAS"
2230{
2231  return "\r	stc	sr,r0"		"\n"
2232	 "	mov	r0,%2"		"\n"
2233	 "	or	#0xF0,r0"	"\n"
2234	 "	ldc	r0,sr"		"\n"
2235	 "	mov.b	@%0,r0"		"\n"
2236	 "	mov.b	%1,@%0"		"\n"
2237	 "	ldc	%2,sr"		"\n"
2238	 "	tst	r0,r0";
2239}
2240  [(set_attr "length" "16")])
2241
2242(define_insn "atomic_test_and_set_hard"
2243  [(set (reg:SI T_REG)
2244	(eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
2245	       (const_int 0)))
2246   (set (mem:QI (match_dup 0))
2247	(unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
2248   (clobber (reg:SI R0_REG))
2249   (clobber (match_scratch:SI 2 "=&r"))
2250   (clobber (match_scratch:SI 3 "=&r"))
2251   (clobber (match_scratch:SI 4 "=0"))]
2252  "TARGET_ATOMIC_HARD_LLCS && !TARGET_ENABLE_TAS"
2253{
2254  return "\r	mov	#-4,%2"		"\n"
2255	 "	and	%0,%2"		"\n"
2256	 "	xor	%2,%0"		"\n"
2257	 "	add	r15,%0"		"\n"
2258	 "	add	#-4,%0"		"\n"
2259	 "0:	movli.l	@%2,r0"		"\n"
2260	 "	mov.l	r0,@-r15"	"\n"
2261	 "	mov.b	@%0,%3"		"\n"
2262	 "	mov.b	%1,@%0"		"\n"
2263	 "	mov.l	@r15+,r0"	"\n"
2264	 "	movco.l	r0,@%2"		"\n"
2265	 "	bf	0b"		"\n"
2266	 "	tst	%3,%3";
2267}
2268  [(set_attr "length" "26")])
2269
2270