]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/sh/sync.md
re PR target/64660 ([SH] Convert atomic_fetch_<op> to atomic_<op>_fetch)
[thirdparty/gcc.git] / gcc / config / sh / sync.md
1 ;; GCC machine description for SH synchronization instructions.
2 ;; Copyright (C) 2011-2015 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 (define_expand "atomic_compare_and_swap<mode>"
213 [(match_operand:SI 0 "arith_reg_dest") ;; bool success output
214 (match_operand:QIHISI 1 "arith_reg_dest") ;; oldval output
215 (match_operand:QIHISI 2 "memory_operand") ;; memory
216 (match_operand:QIHISI 3 "atomic_arith_operand_0") ;; expected input
217 (match_operand:QIHISI 4 "atomic_arith_operand_0") ;; newval input
218 (match_operand:SI 5 "const_int_operand") ;; is_weak
219 (match_operand:SI 6 "const_int_operand") ;; success model
220 (match_operand:SI 7 "const_int_operand")] ;; failure model
221 "TARGET_ATOMIC_ANY"
222 {
223 rtx addr = force_reg (Pmode, XEXP (operands[2], 0));
224 rtx old_val = gen_lowpart (SImode, operands[1]);
225 rtx exp_val = operands[3];
226 rtx new_val = operands[4];
227 rtx atomic_insn;
228
229 if (TARGET_ATOMIC_HARD_LLCS
230 || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
231 atomic_insn = gen_atomic_compare_and_swap<mode>_hard (old_val, addr,
232 exp_val, new_val);
233 else if (TARGET_ATOMIC_SOFT_GUSA)
234 atomic_insn = gen_atomic_compare_and_swap<mode>_soft_gusa (old_val, addr,
235 exp_val, new_val);
236 else if (TARGET_ATOMIC_SOFT_TCB)
237 atomic_insn = gen_atomic_compare_and_swap<mode>_soft_tcb (old_val, addr,
238 exp_val, new_val, TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
239 else if (TARGET_ATOMIC_SOFT_IMASK)
240 atomic_insn = gen_atomic_compare_and_swap<mode>_soft_imask (old_val, addr,
241 exp_val, new_val);
242 else
243 FAIL;
244
245 emit_insn (atomic_insn);
246
247 if (<MODE>mode == QImode)
248 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[1]),
249 operands[1]));
250 else if (<MODE>mode == HImode)
251 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[1]),
252 operands[1]));
253 emit_insn (gen_movsi (operands[0], gen_rtx_REG (SImode, T_REG)));
254 DONE;
255 })
256
257 (define_insn "atomic_compare_and_swapsi_hard"
258 [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
259 (unspec_volatile:SI
260 [(mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
261 (match_operand:SI 2 "arith_operand" "rI08")
262 (match_operand:SI 3 "arith_operand" "rI08")]
263 UNSPECV_CMPXCHG_1))
264 (set (mem:SI (match_dup 1))
265 (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_2))
266 (set (reg:SI T_REG)
267 (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
268 (clobber (reg:SI R0_REG))]
269 "TARGET_ATOMIC_HARD_LLCS
270 || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
271 {
272 return "\r0: movli.l @%1,r0" "\n"
273 " cmp/eq %2,r0" "\n"
274 " bf{.|/}s 0f" "\n"
275 " mov r0,%0" "\n"
276 " mov %3,r0" "\n"
277 " movco.l r0,@%1" "\n"
278 " bf 0b" "\n"
279 "0:";
280 }
281 [(set_attr "length" "14")])
282
283 (define_insn "atomic_compare_and_swap<mode>_hard"
284 [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
285 (unspec_volatile:SI
286 [(mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
287 (match_operand:QIHI 2 "arith_reg_operand" "r")
288 (match_operand:QIHI 3 "arith_reg_operand" "r")]
289 UNSPECV_CMPXCHG_1))
290 (set (mem:QIHI (match_dup 1))
291 (unspec_volatile:QIHI [(const_int 0)] UNSPECV_CMPXCHG_2))
292 (set (reg:SI T_REG)
293 (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
294 (clobber (reg:SI R0_REG))
295 (clobber (match_scratch:SI 4 "=&r"))
296 (clobber (match_scratch:SI 5 "=&r"))
297 (clobber (match_scratch:SI 6 "=1"))]
298 "TARGET_ATOMIC_HARD_LLCS"
299 {
300 return "\r mov #-4,%5" "\n"
301 " <i124extend_insn> %2,%4" "\n"
302 " and %1,%5" "\n"
303 " xor %5,%1" "\n"
304 " add r15,%1" "\n"
305 " add #-4,%1" "\n"
306 "0: movli.l @%5,r0" "\n"
307 " mov.l r0,@-r15" "\n"
308 " mov.<bw> @%1,%0" "\n"
309 " mov.<bw> %3,@%1" "\n"
310 " cmp/eq %4,%0" "\n"
311 " bf{.|/}s 0f" "\n"
312 " mov.l @r15+,r0" "\n"
313 " movco.l r0,@%5" "\n"
314 " bf 0b" "\n"
315 "0:";
316 }
317 [(set_attr "length" "30")])
318
319 (define_insn "atomic_compare_and_swap<mode>_soft_gusa"
320 [(set (match_operand:SI 0 "arith_reg_dest" "=&u")
321 (unspec_volatile:SI
322 [(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u"))
323 (match_operand:QIHISI 2 "arith_reg_operand" "u")
324 (match_operand:QIHISI 3 "arith_reg_operand" "u")]
325 UNSPECV_CMPXCHG_1))
326 (set (mem:QIHISI (match_dup 1))
327 (unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
328 (set (reg:SI T_REG)
329 (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
330 (clobber (match_scratch:SI 4 "=&u"))
331 (clobber (reg:SI R0_REG))
332 (clobber (reg:SI R1_REG))]
333 "TARGET_ATOMIC_SOFT_GUSA"
334 {
335 return "\r mova 1f,r0" "\n"
336 " <i124extend_insn> %2,%4" "\n"
337 " .align 2" "\n"
338 " mov r15,r1" "\n"
339 " mov #(0f-1f),r15" "\n"
340 "0: mov.<bwl> @%1,%0" "\n"
341 " cmp/eq %0,%4" "\n"
342 " bf 1f" "\n"
343 " mov.<bwl> %3,@%1" "\n"
344 "1: mov r1,r15";
345 }
346 [(set_attr "length" "20")])
347
348 (define_insn "atomic_compare_and_swap<mode>_soft_tcb"
349 [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
350 (unspec_volatile:SI
351 [(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
352 (match_operand:QIHISI 2 "arith_reg_operand" "r")
353 (match_operand:QIHISI 3 "arith_reg_operand" "r")]
354 UNSPECV_CMPXCHG_1))
355 (set (mem:QIHISI (match_dup 1))
356 (unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
357 (set (reg:SI T_REG)
358 (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
359 (use (match_operand:SI 4 "gbr_displacement"))
360 (clobber (match_scratch:SI 5 "=&r"))
361 (clobber (reg:SI R0_REG))
362 (clobber (reg:SI R1_REG))]
363 "TARGET_ATOMIC_SOFT_TCB"
364 {
365 return "\r mova 1f,r0" "\n"
366 " .align 2" "\n"
367 " <i124extend_insn> %2,%5" "\n"
368 " mov #(0f-1f),r1" "\n"
369 " mov.l r0,@(%O4,gbr)" "\n"
370 "0: mov.<bwl> @%1,%0" "\n"
371 " mov #0,r0" "\n"
372 " cmp/eq %0,%5" "\n"
373 " bf 1f" "\n"
374 " mov.<bwl> %3,@%1" "\n"
375 "1: mov.l r0,@(%O4,gbr)";
376 }
377 [(set_attr "length" "22")])
378
379 (define_insn "atomic_compare_and_swap<mode>_soft_imask"
380 [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
381 (unspec_volatile:SI
382 [(mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
383 (match_operand:QIHISI 2 "arith_reg_operand" "r")
384 (match_operand:QIHISI 3 "arith_reg_operand" "r")]
385 UNSPECV_CMPXCHG_1))
386 (set (mem:QIHISI (match_dup 1))
387 (unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
388 (set (reg:SI T_REG)
389 (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
390 (clobber (match_scratch:SI 4 "=&r"))
391 (clobber (match_scratch:SI 5 "=&r"))]
392 "TARGET_ATOMIC_SOFT_IMASK"
393 {
394 /* The comparison result is supposed to be in T_REG.
395 Notice that restoring SR will overwrite the T_REG. We handle this by
396 rotating the T_REG into the saved SR before restoring SR. On SH2A we
397 can do one insn shorter by using the bst insn. */
398 if (!TARGET_SH2A)
399 return "\r stc sr,%0" "\n"
400 " <i124extend_insn> %2,%4" "\n"
401 " mov %0,%5" "\n"
402 " or #0xF0,%0" "\n"
403 " shlr %5" "\n"
404 " ldc %0,sr" "\n"
405 " mov.<bwl> @%1,%0" "\n"
406 " cmp/eq %4,%0" "\n"
407 " bf 1f" "\n"
408 " mov.<bwl> %3,@%1" "\n"
409 "1: rotcl %5" "\n"
410 " ldc %5,sr";
411 else
412 return "\r stc sr,%0" "\n"
413 " <i124extend_insn> %2,%4" "\n"
414 " mov %0,%5" "\n"
415 " or #0xF0,%0" "\n"
416 " ldc %0,sr" "\n"
417 " mov.<bwl> @%1,%0" "\n"
418 " cmp/eq %4,%0" "\n"
419 " bst #0,%5" "\n"
420 " bf 1f" "\n"
421 " mov.<bwl> %3,@%1" "\n"
422 "1: ldc %5,sr";
423 }
424 [(set (attr "length") (if_then_else (match_test "!TARGET_SH2A")
425 (const_string "24")
426 (const_string "22")))])
427
428 ;;------------------------------------------------------------------------------
429 ;; read - write - return old value
430
431 (define_expand "atomic_exchange<mode>"
432 [(match_operand:QIHISI 0 "arith_reg_dest") ;; oldval output
433 (match_operand:QIHISI 1 "memory_operand") ;; memory
434 (match_operand:QIHISI 2 "atomic_arith_operand_0") ;; newval input
435 (match_operand:SI 3 "const_int_operand")] ;; memory model
436 "TARGET_ATOMIC_ANY"
437 {
438 rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
439 rtx val = operands[2];
440 rtx atomic_insn;
441
442 if (TARGET_ATOMIC_HARD_LLCS
443 || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
444 atomic_insn = gen_atomic_exchange<mode>_hard (operands[0], addr, val);
445 else if (TARGET_ATOMIC_SOFT_GUSA)
446 atomic_insn = gen_atomic_exchange<mode>_soft_gusa (operands[0], addr, val);
447 else if (TARGET_ATOMIC_SOFT_TCB)
448 atomic_insn = gen_atomic_exchange<mode>_soft_tcb (operands[0], addr, val,
449 TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
450 else if (TARGET_ATOMIC_SOFT_IMASK)
451 atomic_insn = gen_atomic_exchange<mode>_soft_imask (operands[0], addr, val);
452 else
453 FAIL;
454
455 emit_insn (atomic_insn);
456
457 if (<MODE>mode == QImode)
458 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
459 operands[0]));
460 else if (<MODE>mode == HImode)
461 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
462 operands[0]));
463 DONE;
464 })
465
466 (define_insn "atomic_exchangesi_hard"
467 [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
468 (mem:SI (match_operand:SI 1 "arith_reg_operand" "r")))
469 (set (mem:SI (match_dup 1))
470 (unspec:SI
471 [(match_operand:SI 2 "arith_operand" "rI08")] UNSPEC_ATOMIC))
472 (set (reg:SI T_REG) (const_int 1))
473 (clobber (reg:SI R0_REG))]
474 "TARGET_ATOMIC_HARD_LLCS
475 || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
476 {
477 return "\r0: movli.l @%1,r0" "\n"
478 " mov r0,%0" "\n"
479 " mov %2,r0" "\n"
480 " movco.l r0,@%1" "\n"
481 " bf 0b";
482 }
483 [(set_attr "length" "10")])
484
485 (define_insn "atomic_exchange<mode>_hard"
486 [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
487 (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
488 (set (mem:QIHI (match_dup 1))
489 (unspec:QIHI
490 [(match_operand:QIHI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC))
491 (set (reg:SI T_REG) (const_int 1))
492 (clobber (reg:SI R0_REG))
493 (clobber (match_scratch:SI 3 "=&r"))
494 (clobber (match_scratch:SI 4 "=1"))]
495 "TARGET_ATOMIC_HARD_LLCS"
496 {
497 return "\r mov #-4,%3" "\n"
498 " and %1,%3" "\n"
499 " xor %3,%1" "\n"
500 " add r15,%1" "\n"
501 " add #-4,%1" "\n"
502 "0: movli.l @%3,r0" "\n"
503 " mov.l r0,@-r15" "\n"
504 " mov.<bw> @%1,%0" "\n"
505 " mov.<bw> %2,@%1" "\n"
506 " mov.l @r15+,r0" "\n"
507 " movco.l r0,@%3" "\n"
508 " bf 0b";
509 }
510 [(set_attr "length" "24")])
511
512 (define_insn "atomic_exchange<mode>_soft_gusa"
513 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
514 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u")))
515 (set (mem:QIHISI (match_dup 1))
516 (unspec:QIHISI
517 [(match_operand:QIHISI 2 "arith_reg_operand" "u")] UNSPEC_ATOMIC))
518 (clobber (reg:SI R0_REG))
519 (clobber (reg:SI R1_REG))]
520 "TARGET_ATOMIC_SOFT_GUSA"
521 {
522 return "\r mova 1f,r0" "\n"
523 " .align 2" "\n"
524 " mov r15,r1" "\n"
525 " mov #(0f-1f),r15" "\n"
526 "0: mov.<bwl> @%1,%0" "\n"
527 " mov.<bwl> %2,@%1" "\n"
528 "1: mov r1,r15";
529 }
530 [(set_attr "length" "14")])
531
532 (define_insn "atomic_exchange<mode>_soft_tcb"
533 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
534 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
535 (set (mem:QIHISI (match_dup 1))
536 (unspec:QIHISI
537 [(match_operand:QIHISI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC))
538 (clobber (reg:SI R0_REG))
539 (clobber (reg:SI R1_REG))
540 (use (match_operand:SI 3 "gbr_displacement"))]
541 "TARGET_ATOMIC_SOFT_TCB"
542 {
543 return "\r mova 1f,r0" "\n"
544 " mov #(0f-1f),r1" "\n"
545 " .align 2" "\n"
546 " mov.l r0,@(%O3,gbr)" "\n"
547 "0: mov.<bwl> @%1,%0" "\n"
548 " mov #0,r0" "\n"
549 " mov.<bwl> %2,@%1" "\n"
550 "1: mov.l r0,@(%O3,gbr)";
551 }
552 [(set_attr "length" "16")])
553
554 (define_insn "atomic_exchange<mode>_soft_imask"
555 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
556 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
557 (set (mem:QIHISI (match_dup 1))
558 (unspec:QIHISI
559 [(match_operand:QIHISI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC))
560 (clobber (match_scratch:SI 3 "=&r"))]
561 "TARGET_ATOMIC_SOFT_IMASK"
562 {
563 return "\r stc sr,%0" "\n"
564 " mov %0,%3" "\n"
565 " or #0xF0,%0" "\n"
566 " ldc %0,sr" "\n"
567 " mov.<bwl> @%1,%0" "\n"
568 " mov.<bwl> %2,@%1" "\n"
569 " ldc %3,sr";
570 }
571 [(set_attr "length" "14")])
572
573 ;;------------------------------------------------------------------------------
574 ;; read - add|sub|or|and|xor|nand - write - return old value
575
576 ;; atomic_arith_operand_1 can be used by any atomic type for a plus op,
577 ;; since there's no r0 restriction.
578 (define_predicate "atomic_arith_operand_1"
579 (and (match_code "subreg,reg,const_int")
580 (ior (match_operand 0 "arith_reg_operand")
581 (match_test "satisfies_constraint_I08 (op)"))))
582
583 ;; atomic_logic_operand_1 can be used by the hard_llcs, tcb and soft_imask
584 ;; patterns only due to its r0 restriction.
585 (define_predicate "atomic_logical_operand_1"
586 (and (match_code "subreg,reg,const_int")
587 (ior (match_operand 0 "arith_reg_operand")
588 (and (match_test "satisfies_constraint_K08 (op)")
589 (ior (match_test "TARGET_ATOMIC_HARD_LLCS")
590 (match_test "TARGET_ATOMIC_SOFT_IMASK")
591 (match_test "TARGET_ATOMIC_SOFT_TCB")
592 (match_test "TARGET_ATOMIC_ANY && TARGET_SH4A
593 && mode == SImode
594 && !TARGET_ATOMIC_STRICT"))))))
595
596 (define_code_attr fetchop_predicate_1
597 [(plus "atomic_arith_operand_1") (minus "arith_reg_operand")
598 (ior "atomic_logical_operand_1") (xor "atomic_logical_operand_1")
599 (and "atomic_logical_operand_1")])
600
601 (define_code_attr fetchop_constraint_1_llcs
602 [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
603
604 (define_code_attr fetchop_constraint_1_gusa
605 [(plus "uI08") (minus "u") (ior "u") (xor "u") (and "u")])
606
607 (define_code_attr fetchop_constraint_1_tcb
608 [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
609
610 (define_code_attr fetchop_constraint_1_imask
611 [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
612
613 (define_expand "atomic_fetch_<fetchop_name><mode>"
614 [(set (match_operand:QIHISI 0 "arith_reg_dest")
615 (match_operand:QIHISI 1 "memory_operand"))
616 (set (match_dup 1)
617 (unspec:QIHISI
618 [(FETCHOP:QIHISI (match_dup 1)
619 (match_operand:QIHISI 2 "<fetchop_predicate_1>"))]
620 UNSPEC_ATOMIC))
621 (match_operand:SI 3 "const_int_operand")]
622 "TARGET_ATOMIC_ANY"
623 {
624 rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
625 rtx atomic_insn;
626
627 if (TARGET_ATOMIC_HARD_LLCS
628 || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
629 atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_hard (operands[0], addr,
630 operands[2]);
631 else if (TARGET_ATOMIC_SOFT_GUSA)
632 atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_gusa (operands[0],
633 addr, operands[2]);
634 else if (TARGET_ATOMIC_SOFT_TCB)
635 atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_tcb (operands[0],
636 addr, operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
637 else if (TARGET_ATOMIC_SOFT_IMASK)
638 atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_imask (operands[0],
639 addr, operands[2]);
640 else
641 FAIL;
642
643 emit_insn (atomic_insn);
644
645 if (<MODE>mode == QImode)
646 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
647 operands[0]));
648 else if (<MODE>mode == HImode)
649 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
650 operands[0]));
651 DONE;
652 })
653
654 (define_insn_and_split "atomic_fetch_<fetchop_name>si_hard"
655 [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
656 (mem:SI (match_operand:SI 1 "arith_reg_operand" "r")))
657 (set (mem:SI (match_dup 1))
658 (unspec:SI
659 [(FETCHOP:SI (mem:SI (match_dup 1))
660 (match_operand:SI 2 "<fetchop_predicate_1>"
661 "<fetchop_constraint_1_llcs>"))]
662 UNSPEC_ATOMIC))
663 (set (reg:SI T_REG) (const_int 1))
664 (clobber (reg:SI R0_REG))]
665 "TARGET_ATOMIC_HARD_LLCS
666 || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
667 {
668 return "\r0: movli.l @%1,r0" "\n"
669 " mov r0,%0" "\n"
670 " <fetchop_name> %2,r0" "\n"
671 " movco.l r0,@%1" "\n"
672 " bf 0b";
673 }
674 "&& can_create_pseudo_p () && optimize
675 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
676 [(const_int 0)]
677 {
678 emit_insn (gen_atomic_<fetchop_name>_fetchsi_hard (gen_reg_rtx (SImode),
679 operands[1], operands[2]));
680 }
681 [(set_attr "length" "10")])
682
683 ;; Combine pattern for xor (val, -1) / nand (val, -1).
684 (define_insn_and_split "atomic_fetch_notsi_hard"
685 [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
686 (mem:SI (match_operand:SI 1 "arith_reg_operand" "r")))
687 (set (mem:SI (match_dup 1))
688 (unspec:SI [(not:SI (mem:SI (match_dup 1)))] UNSPEC_ATOMIC))
689 (set (reg:SI T_REG) (const_int 1))
690 (clobber (reg:SI R0_REG))]
691 "TARGET_ATOMIC_HARD_LLCS
692 || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
693 {
694 return "\r0: movli.l @%1,r0" "\n"
695 " mov r0,%0" "\n"
696 " not r0,r0" "\n"
697 " movco.l r0,@%1" "\n"
698 " bf 0b";
699 }
700 "&& can_create_pseudo_p () && optimize
701 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
702 [(const_int 0)]
703 {
704 emit_insn (gen_atomic_not_fetchsi_hard (gen_reg_rtx (SImode), operands[1]));
705 }
706 [(set_attr "length" "10")])
707
708 (define_insn_and_split "atomic_fetch_<fetchop_name><mode>_hard"
709 [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
710 (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
711 (set (mem:QIHI (match_dup 1))
712 (unspec:QIHI
713 [(FETCHOP:QIHI (mem:QIHI (match_dup 1))
714 (match_operand:QIHI 2 "<fetchop_predicate_1>"
715 "<fetchop_constraint_1_llcs>"))]
716 UNSPEC_ATOMIC))
717 (set (reg:SI T_REG) (const_int 1))
718 (clobber (reg:SI R0_REG))
719 (clobber (match_scratch:SI 3 "=&r"))
720 (clobber (match_scratch:SI 4 "=1"))]
721 "TARGET_ATOMIC_HARD_LLCS"
722 {
723 return "\r mov #-4,%3" "\n"
724 " and %1,%3" "\n"
725 " xor %3,%1" "\n"
726 " add r15,%1" "\n"
727 " add #-4,%1" "\n"
728 "0: movli.l @%3,r0" "\n"
729 " mov.l r0,@-r15" "\n"
730 " mov.<bw> @%1,r0" "\n"
731 " mov r0,%0" "\n"
732 " <fetchop_name> %2,r0" "\n"
733 " mov.<bw> r0,@%1" "\n"
734 " mov.l @r15+,r0" "\n"
735 " movco.l r0,@%3" "\n"
736 " bf 0b";
737 }
738 "&& can_create_pseudo_p () && optimize
739 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
740 [(const_int 0)]
741 {
742 emit_insn (gen_atomic_<fetchop_name><mode>_hard (operands[1], operands[2]));
743 }
744 [(set_attr "length" "28")])
745
746 (define_insn "atomic_<fetchop_name><mode>_hard"
747 [(set (mem:QIHI (match_operand:SI 0 "arith_reg_operand" "r"))
748 (unspec:QIHI
749 [(FETCHOP:QIHI (mem:QIHI (match_dup 0))
750 (match_operand:QIHI 1 "<fetchop_predicate_1>"
751 "<fetchop_constraint_1_llcs>"))]
752 UNSPEC_ATOMIC))
753 (set (reg:SI T_REG) (const_int 1))
754 (clobber (reg:SI R0_REG))
755 (clobber (match_scratch:SI 2 "=&r"))
756 (clobber (match_scratch:SI 3 "=0"))]
757 "TARGET_ATOMIC_HARD_LLCS"
758 {
759 return "\r mov #-4,%2" "\n"
760 " and %0,%2" "\n"
761 " xor %2,%0" "\n"
762 " add r15,%0" "\n"
763 " add #-4,%0" "\n"
764 "0: movli.l @%2,r0" "\n"
765 " mov.l r0,@-r15" "\n"
766 " mov.<bw> @%0,r0" "\n"
767 " <fetchop_name> %1,r0" "\n"
768 " mov.<bw> r0,@%0" "\n"
769 " mov.l @r15+,r0" "\n"
770 " movco.l r0,@%2" "\n"
771 " bf 0b";
772 }
773 [(set_attr "length" "26")])
774
775 ;; Combine pattern for xor (val, -1) / nand (val, -1).
776 (define_insn_and_split "atomic_fetch_not<mode>_hard"
777 [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
778 (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
779 (set (mem:QIHI (match_dup 1))
780 (unspec:QIHI [(not:QIHI (mem:QIHI (match_dup 1)))] UNSPEC_ATOMIC))
781 (set (reg:SI T_REG) (const_int 1))
782 (clobber (reg:SI R0_REG))
783 (clobber (match_scratch:SI 2 "=&r"))
784 (clobber (match_scratch:SI 3 "=1"))]
785 "TARGET_ATOMIC_HARD_LLCS"
786 {
787 return "\r mov #-4,%2" "\n"
788 " and %1,%2" "\n"
789 " xor %2,%1" "\n"
790 " add r15,%1" "\n"
791 " add #-4,%1" "\n"
792 "0: movli.l @%2,r0" "\n"
793 " mov.l r0,@-r15" "\n"
794 " mov.<bw> @%1,%0" "\n"
795 " not %0,r0" "\n"
796 " mov.<bw> r0,@%1" "\n"
797 " mov.l @r15+,r0" "\n"
798 " movco.l r0,@%2" "\n"
799 " bf 0b";
800 }
801 "&& can_create_pseudo_p () && optimize
802 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
803 [(const_int 0)]
804 {
805 emit_insn (gen_atomic_not<mode>_hard (operands[1]));
806 }
807 [(set_attr "length" "26")])
808
809 (define_insn "atomic_not<mode>_hard"
810 [(set (mem:QIHI (match_operand:SI 0 "arith_reg_operand" "r"))
811 (unspec:QIHI [(not:QIHI (mem:QIHI (match_dup 0)))] UNSPEC_ATOMIC))
812 (set (reg:SI T_REG) (const_int 1))
813 (clobber (reg:SI R0_REG))
814 (clobber (match_scratch:SI 1 "=&r"))
815 (clobber (match_scratch:SI 2 "=0"))]
816 "TARGET_ATOMIC_HARD_LLCS"
817 {
818 return "\r mov #-4,%1" "\n"
819 " and %0,%1" "\n"
820 " xor %1,%0" "\n"
821 " add r15,%0" "\n"
822 " add #-4,%0" "\n"
823 "0: movli.l @%1,r0" "\n"
824 " mov.l r0,@-r15" "\n"
825 " mov.<bw> @%0,r0" "\n"
826 " not r0,r0" "\n"
827 " mov.<bw> r0,@%0" "\n"
828 " mov.l @r15+,r0" "\n"
829 " movco.l r0,@%1" "\n"
830 " bf 0b";
831 }
832 [(set_attr "length" "26")])
833
834 (define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_gusa"
835 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
836 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u")))
837 (set (mem:QIHISI (match_dup 1))
838 (unspec:QIHISI
839 [(FETCHOP:QIHISI
840 (mem:QIHISI (match_dup 1))
841 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
842 "<fetchop_constraint_1_gusa>"))]
843 UNSPEC_ATOMIC))
844 (clobber (match_scratch:QIHISI 3 "=&u"))
845 (clobber (reg:SI R0_REG))
846 (clobber (reg:SI R1_REG))]
847 "TARGET_ATOMIC_SOFT_GUSA"
848 {
849 return "\r mova 1f,r0" "\n"
850 " .align 2" "\n"
851 " mov r15,r1" "\n"
852 " mov #(0f-1f),r15" "\n"
853 "0: mov.<bwl> @%1,%0" "\n"
854 " mov %0,%3" "\n"
855 " <fetchop_name> %2,%3" "\n"
856 " mov.<bwl> %3,@%1" "\n"
857 "1: mov r1,r15";
858 }
859 "&& can_create_pseudo_p () && optimize
860 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
861 [(const_int 0)]
862 {
863 emit_insn (gen_atomic_<fetchop_name>_fetch<mode>_soft_gusa (
864 gen_reg_rtx (<MODE>mode), operands[1], operands[2]));
865 }
866 [(set_attr "length" "18")])
867
868 ;; Combine pattern for xor (val, -1) / nand (val, -1).
869 (define_insn_and_split "atomic_fetch_not<mode>_soft_gusa"
870 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
871 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u")))
872 (set (mem:QIHISI (match_dup 1))
873 (unspec:QIHISI [(not:QIHISI (mem:QIHISI (match_dup 1)))] UNSPEC_ATOMIC))
874 (clobber (match_scratch:QIHISI 2 "=&u"))
875 (clobber (reg:SI R0_REG))
876 (clobber (reg:SI R1_REG))]
877 "TARGET_ATOMIC_SOFT_GUSA"
878 {
879 return "\r mova 1f,r0" "\n"
880 " mov r15,r1" "\n"
881 " .align 2" "\n"
882 " mov #(0f-1f),r15" "\n"
883 "0: mov.<bwl> @%1,%0" "\n"
884 " not %0,%2" "\n"
885 " mov.<bwl> %2,@%1" "\n"
886 "1: mov r1,r15";
887 }
888 "&& can_create_pseudo_p () && optimize
889 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
890 [(const_int 0)]
891 {
892 emit_insn (gen_atomic_not_fetch<mode>_soft_gusa (gen_reg_rtx (<MODE>mode),
893 operands[1]));
894 }
895 [(set_attr "length" "16")])
896
897 (define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_tcb"
898 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
899 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
900 (set (mem:QIHISI (match_dup 1))
901 (unspec:QIHISI
902 [(FETCHOP:QIHISI
903 (mem:QIHISI (match_dup 1))
904 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
905 "<fetchop_constraint_1_tcb>"))]
906 UNSPEC_ATOMIC))
907 (use (match_operand:SI 3 "gbr_displacement"))
908 (clobber (reg:SI R0_REG))
909 (clobber (reg:SI R1_REG))]
910 "TARGET_ATOMIC_SOFT_TCB"
911 {
912 return "\r mova 1f,r0" "\n"
913 " .align 2" "\n"
914 " mov #(0f-1f),r1" "\n"
915 " mov.l r0,@(%O3,gbr)" "\n"
916 "0: mov.<bwl> @%1,r0" "\n"
917 " mov r0,%0" "\n"
918 " <fetchop_name> %2,r0" "\n"
919 " mov.<bwl> r0,@%1" "\n"
920 "1: mov #0,r0" "\n"
921 " mov.l r0,@(%O3,gbr)";
922 }
923 "&& can_create_pseudo_p () && optimize
924 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
925 [(const_int 0)]
926 {
927 emit_insn (gen_atomic_<fetchop_name><mode>_soft_tcb (
928 operands[1], operands[2], operands[3]));
929 }
930 [(set_attr "length" "20")])
931
932 (define_insn "atomic_<fetchop_name><mode>_soft_tcb"
933 [(set (mem:QIHISI (match_operand:SI 0 "arith_reg_operand" "r"))
934 (unspec:QIHISI
935 [(FETCHOP:QIHISI
936 (mem:QIHISI (match_dup 0))
937 (match_operand:QIHISI 1 "<fetchop_predicate_1>"
938 "<fetchop_constraint_1_tcb>"))]
939 UNSPEC_ATOMIC))
940 (use (match_operand:SI 2 "gbr_displacement"))
941 (clobber (reg:SI R0_REG))
942 (clobber (reg:SI R1_REG))]
943 "TARGET_ATOMIC_SOFT_TCB"
944 {
945 return "\r mova 1f,r0" "\n"
946 " mov #(0f-1f),r1" "\n"
947 " .align 2" "\n"
948 " mov.l r0,@(%O2,gbr)" "\n"
949 "0: mov.<bwl> @%0,r0" "\n"
950 " <fetchop_name> %1,r0" "\n"
951 " mov.<bwl> r0,@%0" "\n"
952 "1: mov #0,r0" "\n"
953 " mov.l r0,@(%O2,gbr)";
954 }
955 [(set_attr "length" "18")])
956
957 ;; Combine pattern for xor (val, -1) / nand (val, -1).
958 (define_insn_and_split "atomic_fetch_not<mode>_soft_tcb"
959 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
960 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
961 (set (mem:QIHISI (match_dup 1))
962 (unspec:QIHISI [(not:QIHISI (mem:QIHISI (match_dup 1)))] UNSPEC_ATOMIC))
963 (use (match_operand:SI 2 "gbr_displacement"))
964 (clobber (reg:SI R0_REG))
965 (clobber (reg:SI R1_REG))]
966 "TARGET_ATOMIC_SOFT_TCB"
967 {
968 return "\r mova 1f,r0" "\n"
969 " .align 2" "\n"
970 " mov #(0f-1f),r1" "\n"
971 " mov.l r0,@(%O2,gbr)" "\n"
972 "0: mov.<bwl> @%1,r0" "\n"
973 " mov r0,%0" "\n"
974 " not r0,r0" "\n"
975 " mov.<bwl> r0,@%1" "\n"
976 "1: mov #0,r0" "\n"
977 " mov.l r0,@(%O2,gbr)";
978 }
979 "&& can_create_pseudo_p () && optimize
980 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
981 [(const_int 0)]
982 {
983 emit_insn (gen_atomic_not<mode>_soft_tcb (operands[1], operands[2]));
984 }
985 [(set_attr "length" "20")])
986
987 (define_insn "atomic_not<mode>_soft_tcb"
988 [(set (mem:QIHISI (match_operand:SI 0 "arith_reg_operand" "r"))
989 (unspec:QIHISI [(not:QIHISI (mem:QIHISI (match_dup 0)))] UNSPEC_ATOMIC))
990 (use (match_operand:SI 1 "gbr_displacement"))
991 (clobber (reg:SI R0_REG))
992 (clobber (reg:SI R1_REG))]
993 "TARGET_ATOMIC_SOFT_TCB"
994 {
995 return "\r mova 1f,r0" "\n"
996 " mov #(0f-1f),r1" "\n"
997 " .align 2" "\n"
998 " mov.l r0,@(%O1,gbr)" "\n"
999 "0: mov.<bwl> @%0,r0" "\n"
1000 " not r0,r0" "\n"
1001 " mov.<bwl> r0,@%0" "\n"
1002 "1: mov #0,r0" "\n"
1003 " mov.l r0,@(%O1,gbr)";
1004 }
1005 [(set_attr "length" "18")])
1006
1007 (define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_imask"
1008 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1009 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
1010 (set (mem:QIHISI (match_dup 1))
1011 (unspec:QIHISI
1012 [(FETCHOP:QIHISI
1013 (mem:QIHISI (match_dup 1))
1014 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1015 "<fetchop_constraint_1_imask>"))]
1016 UNSPEC_ATOMIC))
1017 (clobber (reg:SI R0_REG))
1018 (clobber (match_scratch:QIHISI 3 "=&r"))]
1019 "TARGET_ATOMIC_SOFT_IMASK"
1020 {
1021 return "\r stc sr,r0" "\n"
1022 " mov r0,%3" "\n"
1023 " or #0xF0,r0" "\n"
1024 " ldc r0,sr" "\n"
1025 " mov.<bwl> @%1,r0" "\n"
1026 " mov r0,%0" "\n"
1027 " <fetchop_name> %2,r0" "\n"
1028 " mov.<bwl> r0,@%1" "\n"
1029 " ldc %3,sr";
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_imask (
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_imask"
1042 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1043 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
1044 (set (mem:QIHISI (match_dup 1))
1045 (unspec:QIHISI [(not:QIHISI (mem:QIHISI (match_dup 1)))] UNSPEC_ATOMIC))
1046 (clobber (reg:SI R0_REG))
1047 (clobber (match_scratch:QIHISI 2 "=&r"))]
1048 "TARGET_ATOMIC_SOFT_IMASK"
1049 {
1050 return "\r stc sr,r0" "\n"
1051 " mov r0,%2" "\n"
1052 " or #0xF0,r0" "\n"
1053 " ldc r0,sr" "\n"
1054 " mov.<bwl> @%1,r0" "\n"
1055 " mov r0,%0" "\n"
1056 " not r0,r0" "\n"
1057 " mov.<bwl> r0,@%1" "\n"
1058 " ldc %2,sr";
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_imask (gen_reg_rtx (<MODE>mode),
1065 operands[1]));
1066 }
1067 [(set_attr "length" "18")])
1068
1069 (define_expand "atomic_fetch_nand<mode>"
1070 [(set (match_operand:QIHISI 0 "arith_reg_dest")
1071 (match_operand:QIHISI 1 "memory_operand"))
1072 (set (match_dup 1)
1073 (unspec:QIHISI
1074 [(not:QIHISI (and:QIHISI (match_dup 1)
1075 (match_operand:QIHISI 2 "atomic_logical_operand_1")))]
1076 UNSPEC_ATOMIC))
1077 (match_operand:SI 3 "const_int_operand")]
1078 "TARGET_ATOMIC_ANY"
1079 {
1080 rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
1081 rtx atomic_insn;
1082
1083 if (TARGET_ATOMIC_HARD_LLCS
1084 || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
1085 atomic_insn = gen_atomic_fetch_nand<mode>_hard (operands[0], addr,
1086 operands[2]);
1087 else if (TARGET_ATOMIC_SOFT_GUSA)
1088 atomic_insn = gen_atomic_fetch_nand<mode>_soft_gusa (operands[0], addr,
1089 operands[2]);
1090 else if (TARGET_ATOMIC_SOFT_TCB)
1091 atomic_insn = gen_atomic_fetch_nand<mode>_soft_tcb (operands[0], addr,
1092 operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
1093 else if (TARGET_ATOMIC_SOFT_IMASK)
1094 atomic_insn = gen_atomic_fetch_nand<mode>_soft_imask (operands[0], addr,
1095 operands[2]);
1096 else
1097 FAIL;
1098
1099 emit_insn (atomic_insn);
1100
1101 if (<MODE>mode == QImode)
1102 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
1103 operands[0]));
1104 else if (<MODE>mode == HImode)
1105 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
1106 operands[0]));
1107 DONE;
1108 })
1109
1110 (define_insn_and_split "atomic_fetch_nandsi_hard"
1111 [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
1112 (mem:SI (match_operand:SI 1 "arith_reg_operand" "r")))
1113 (set (mem:SI (match_dup 1))
1114 (unspec:SI
1115 [(not:SI (and:SI (mem:SI (match_dup 1))
1116 (match_operand:SI 2 "logical_operand" "rK08")))]
1117 UNSPEC_ATOMIC))
1118 (set (reg:SI T_REG) (const_int 1))
1119 (clobber (reg:SI R0_REG))]
1120 "TARGET_ATOMIC_HARD_LLCS
1121 || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1122 {
1123 return "\r0: movli.l @%1,r0" "\n"
1124 " mov r0,%0" "\n"
1125 " and %2,r0" "\n"
1126 " not r0,r0" "\n"
1127 " movco.l r0,@%1" "\n"
1128 " bf 0b";
1129 }
1130 "&& can_create_pseudo_p () && optimize
1131 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1132 [(const_int 0)]
1133 {
1134 emit_insn (gen_atomic_nand_fetchsi_hard (gen_reg_rtx (SImode), operands[1],
1135 operands[2]));
1136 }
1137 [(set_attr "length" "12")])
1138
1139 (define_insn_and_split "atomic_fetch_nand<mode>_hard"
1140 [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1141 (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
1142 (set (mem:QIHI (match_dup 1))
1143 (unspec:QIHI
1144 [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1))
1145 (match_operand:QIHI 2 "logical_operand" "rK08")))]
1146 UNSPEC_ATOMIC))
1147 (set (reg:SI T_REG) (const_int 1))
1148 (clobber (reg:SI R0_REG))
1149 (clobber (match_scratch:SI 3 "=&r"))
1150 (clobber (match_scratch:SI 4 "=1"))]
1151 "TARGET_ATOMIC_HARD_LLCS"
1152 {
1153 return "\r mov #-4,%3" "\n"
1154 " and %1,%3" "\n"
1155 " xor %3,%1" "\n"
1156 " add r15,%1" "\n"
1157 " add #-4,%1" "\n"
1158 "0: movli.l @%3,r0" "\n"
1159 " mov.l r0,@-r15" "\n"
1160 " mov.<bw> @%1,r0" "\n"
1161 " mov r0,%0" "\n"
1162 " and %2,r0" "\n"
1163 " not r0,r0" "\n"
1164 " mov.<bw> r0,@%1" "\n"
1165 " mov.l @r15+,r0" "\n"
1166 " movco.l r0,@%3" "\n"
1167 " bf 0b";
1168 }
1169 "&& can_create_pseudo_p () && optimize
1170 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1171 [(const_int 0)]
1172 {
1173 emit_insn (gen_atomic_nand<mode>_hard (operands[1], operands[2]));
1174 }
1175 [(set_attr "length" "30")])
1176
1177 (define_insn "atomic_nand<mode>_hard"
1178 [(set (mem:QIHI (match_operand:SI 0 "arith_reg_operand" "r"))
1179 (unspec:QIHI
1180 [(not:QIHI (and:QIHI (mem:QIHI (match_dup 0))
1181 (match_operand:QIHI 1 "logical_operand" "rK08")))]
1182 UNSPEC_ATOMIC))
1183 (set (reg:SI T_REG) (const_int 1))
1184 (clobber (reg:SI R0_REG))
1185 (clobber (match_scratch:SI 2 "=&r"))
1186 (clobber (match_scratch:SI 3 "=0"))]
1187 "TARGET_ATOMIC_HARD_LLCS"
1188 {
1189 return "\r mov #-4,%2" "\n"
1190 " and %0,%2" "\n"
1191 " xor %2,%0" "\n"
1192 " add r15,%0" "\n"
1193 " add #-4,%0" "\n"
1194 "0: movli.l @%2,r0" "\n"
1195 " mov.l r0,@-r15" "\n"
1196 " mov.<bw> @%0,r0" "\n"
1197 " and %1,r0" "\n"
1198 " not r0,r0" "\n"
1199 " mov.<bw> r0,@%0" "\n"
1200 " mov.l @r15+,r0" "\n"
1201 " movco.l r0,@%2" "\n"
1202 " bf 0b";
1203 }
1204 [(set_attr "length" "28")])
1205
1206 (define_insn_and_split "atomic_fetch_nand<mode>_soft_gusa"
1207 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1208 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u")))
1209 (set (mem:QIHISI (match_dup 1))
1210 (unspec:QIHISI
1211 [(not:QIHISI
1212 (and:QIHISI (mem:QIHISI (match_dup 1))
1213 (match_operand:QIHISI 2 "arith_reg_operand" "u")))]
1214 UNSPEC_ATOMIC))
1215 (clobber (match_scratch:QIHISI 3 "=&u"))
1216 (clobber (reg:SI R0_REG))
1217 (clobber (reg:SI R1_REG))]
1218 "TARGET_ATOMIC_SOFT_GUSA"
1219 {
1220 return "\r mova 1f,r0" "\n"
1221 " mov r15,r1" "\n"
1222 " .align 2" "\n"
1223 " mov #(0f-1f),r15" "\n"
1224 "0: mov.<bwl> @%1,%0" "\n"
1225 " mov %2,%3" "\n"
1226 " and %0,%3" "\n"
1227 " not %3,%3" "\n"
1228 " mov.<bwl> %3,@%1" "\n"
1229 "1: mov r1,r15";
1230 }
1231 "&& can_create_pseudo_p () && optimize
1232 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1233 [(const_int 0)]
1234 {
1235 emit_insn (gen_atomic_nand_fetch<mode>_soft_gusa (gen_reg_rtx (<MODE>mode),
1236 operands[1], operands[2]));
1237 }
1238 [(set_attr "length" "20")])
1239
1240 (define_insn_and_split "atomic_fetch_nand<mode>_soft_tcb"
1241 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1242 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
1243 (set (mem:QIHISI (match_dup 1))
1244 (unspec:QIHISI
1245 [(not:QIHISI
1246 (and:QIHISI (mem:QIHISI (match_dup 1))
1247 (match_operand:QIHISI 2 "logical_operand" "rK08")))]
1248 UNSPEC_ATOMIC))
1249 (use (match_operand:SI 3 "gbr_displacement"))
1250 (clobber (reg:SI R0_REG))
1251 (clobber (reg:SI R1_REG))]
1252 "TARGET_ATOMIC_SOFT_TCB"
1253 {
1254 return "\r mova 1f,r0" "\n"
1255 " mov #(0f-1f),r1" "\n"
1256 " .align 2" "\n"
1257 " mov.l r0,@(%O3,gbr)" "\n"
1258 "0: mov.<bwl> @%1,r0" "\n"
1259 " mov r0,%0" "\n"
1260 " and %2,r0" "\n"
1261 " not r0,r0" "\n"
1262 " mov.<bwl> r0,@%1" "\n"
1263 "1: mov #0,r0" "\n"
1264 " mov.l r0,@(%O3,gbr)";
1265 }
1266 "&& can_create_pseudo_p () && optimize
1267 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1268 [(const_int 0)]
1269 {
1270 emit_insn (gen_atomic_nand<mode>_soft_tcb (operands[1], operands[2],
1271 operands[3]));
1272 }
1273 [(set_attr "length" "22")])
1274
1275 (define_insn "atomic_nand<mode>_soft_tcb"
1276 [(set (mem:QIHISI (match_operand:SI 0 "arith_reg_operand" "r"))
1277 (unspec:QIHISI
1278 [(not:QIHISI
1279 (and:QIHISI (mem:QIHISI (match_dup 0))
1280 (match_operand:QIHISI 1 "logical_operand" "rK08")))]
1281 UNSPEC_ATOMIC))
1282 (use (match_operand:SI 2 "gbr_displacement"))
1283 (clobber (reg:SI R0_REG))
1284 (clobber (reg:SI R1_REG))]
1285 "TARGET_ATOMIC_SOFT_TCB"
1286 {
1287 return "\r mova 1f,r0" "\n"
1288 " .align 2" "\n"
1289 " mov #(0f-1f),r1" "\n"
1290 " mov.l r0,@(%O2,gbr)" "\n"
1291 "0: mov.<bwl> @%0,r0" "\n"
1292 " and %1,r0" "\n"
1293 " not r0,r0" "\n"
1294 " mov.<bwl> r0,@%0" "\n"
1295 "1: mov #0,r0" "\n"
1296 " mov.l r0,@(%O2,gbr)";
1297 }
1298 [(set_attr "length" "20")])
1299
1300 (define_insn_and_split "atomic_fetch_nand<mode>_soft_imask"
1301 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1302 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
1303 (set (mem:QIHISI (match_dup 1))
1304 (unspec:QIHISI
1305 [(not:QIHISI
1306 (and:QIHISI (mem:QIHISI (match_dup 1))
1307 (match_operand:QIHISI 2 "logical_operand" "rK08")))]
1308 UNSPEC_ATOMIC))
1309 (clobber (reg:SI R0_REG))
1310 (clobber (match_scratch:SI 3 "=&r"))]
1311 "TARGET_ATOMIC_SOFT_IMASK"
1312 {
1313 return "\r stc sr,r0" "\n"
1314 " mov r0,%3" "\n"
1315 " or #0xF0,r0" "\n"
1316 " ldc r0,sr" "\n"
1317 " mov.<bwl> @%1,r0" "\n"
1318 " mov r0,%0" "\n"
1319 " and %2,r0" "\n"
1320 " not r0,r0" "\n"
1321 " mov.<bwl> r0,@%1" "\n"
1322 " ldc %3,sr";
1323 }
1324 "&& can_create_pseudo_p () && optimize
1325 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1326 [(const_int 0)]
1327 {
1328 emit_insn (gen_atomic_nand_fetch<mode>_soft_imask (gen_reg_rtx (<MODE>mode),
1329 operands[1], operands[2]));
1330 }
1331 [(set_attr "length" "20")])
1332
1333 ;;------------------------------------------------------------------------------
1334 ;; read - add|sub|or|and|xor|nand - write - return new value
1335
1336 (define_expand "atomic_<fetchop_name>_fetch<mode>"
1337 [(set (match_operand:QIHISI 0 "arith_reg_dest")
1338 (FETCHOP:QIHISI
1339 (match_operand:QIHISI 1 "memory_operand")
1340 (match_operand:QIHISI 2 "<fetchop_predicate_1>")))
1341 (set (match_dup 1)
1342 (unspec:QIHISI
1343 [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))]
1344 UNSPEC_ATOMIC))
1345 (match_operand:SI 3 "const_int_operand" "")]
1346 "TARGET_ATOMIC_ANY"
1347 {
1348 rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
1349 rtx atomic_insn;
1350
1351 if (TARGET_ATOMIC_HARD_LLCS
1352 || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
1353 atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_hard (operands[0], addr,
1354 operands[2]);
1355 else if (TARGET_ATOMIC_SOFT_GUSA)
1356 atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_gusa (operands[0],
1357 addr, operands[2]);
1358 else if (TARGET_ATOMIC_SOFT_TCB)
1359 atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_tcb (operands[0],
1360 addr, operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
1361 else if (TARGET_ATOMIC_SOFT_IMASK)
1362 atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_imask (operands[0],
1363 addr, operands[2]);
1364 else
1365 FAIL;
1366
1367 emit_insn (atomic_insn);
1368
1369 if (<MODE>mode == QImode)
1370 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
1371 operands[0]));
1372 else if (<MODE>mode == HImode)
1373 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
1374 operands[0]));
1375 DONE;
1376 })
1377
1378 (define_insn "atomic_<fetchop_name>_fetchsi_hard"
1379 [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
1380 (FETCHOP:SI
1381 (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
1382 (match_operand:SI 2 "<fetchop_predicate_1>"
1383 "<fetchop_constraint_1_llcs>")))
1384 (set (mem:SI (match_dup 1))
1385 (unspec:SI
1386 [(FETCHOP:SI (mem:SI (match_dup 1)) (match_dup 2))]
1387 UNSPEC_ATOMIC))
1388 (set (reg:SI T_REG) (const_int 1))]
1389 "TARGET_ATOMIC_HARD_LLCS
1390 || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1391 {
1392 return "\r0: movli.l @%1,%0" "\n"
1393 " <fetchop_name> %2,%0" "\n"
1394 " movco.l %0,@%1" "\n"
1395 " bf 0b";
1396 }
1397 [(set_attr "length" "8")])
1398
1399 ;; Combine pattern for xor (val, -1) / nand (val, -1).
1400 (define_insn "atomic_not_fetchsi_hard"
1401 [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
1402 (not:SI (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))))
1403 (set (mem:SI (match_dup 1))
1404 (unspec:SI [(not:SI (mem:SI (match_dup 1)))] UNSPEC_ATOMIC))
1405 (set (reg:SI T_REG) (const_int 1))]
1406 "TARGET_ATOMIC_HARD_LLCS
1407 || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1408 {
1409 return "\r0: movli.l @%1,%0" "\n"
1410 " not %0,%0" "\n"
1411 " movco.l %0,@%1" "\n"
1412 " bf 0b";
1413 }
1414 [(set_attr "length" "8")])
1415
1416 (define_insn_and_split "atomic_<fetchop_name>_fetch<mode>_hard"
1417 [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1418 (FETCHOP:QIHI
1419 (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
1420 (match_operand:QIHI 2 "<fetchop_predicate_1>"
1421 "<fetchop_constraint_1_llcs>")))
1422 (set (mem:QIHI (match_dup 1))
1423 (unspec:QIHI
1424 [(FETCHOP:QIHI (mem:QIHI (match_dup 1)) (match_dup 2))]
1425 UNSPEC_ATOMIC))
1426 (set (reg:SI T_REG) (const_int 1))
1427 (clobber (reg:SI R0_REG))
1428 (clobber (match_scratch:SI 3 "=&r"))
1429 (clobber (match_scratch:SI 4 "=1"))]
1430 "TARGET_ATOMIC_HARD_LLCS"
1431 {
1432 return "\r mov #-4,%3" "\n"
1433 " and %1,%3" "\n"
1434 " xor %3,%1" "\n"
1435 " add r15,%1" "\n"
1436 " add #-4,%1" "\n"
1437 "0: movli.l @%3,r0" "\n"
1438 " mov.l r0,@-r15" "\n"
1439 " mov.<bw> @%1,r0" "\n"
1440 " <fetchop_name> %2,r0" "\n"
1441 " mov.<bw> r0,@%1" "\n"
1442 " mov r0,%0" "\n"
1443 " mov.l @r15+,r0" "\n"
1444 " movco.l r0,@%3" "\n"
1445 " bf 0b";
1446 }
1447 "&& can_create_pseudo_p () && optimize
1448 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1449 [(const_int 0)]
1450 {
1451 emit_insn (gen_atomic_<fetchop_name><mode>_hard (operands[1], operands[2]));
1452 }
1453 [(set_attr "length" "28")])
1454
1455 ;; Combine pattern for xor (val, -1) / nand (val, -1).
1456 (define_insn_and_split "atomic_not_fetch<mode>_hard"
1457 [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1458 (not:QIHI (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))))
1459 (set (mem:QIHI (match_dup 1))
1460 (unspec:QIHI [(not:QIHI (mem:QIHI (match_dup 1)))] UNSPEC_ATOMIC))
1461 (set (reg:SI T_REG) (const_int 1))
1462 (clobber (reg:SI R0_REG))
1463 (clobber (match_scratch:SI 2 "=&r"))
1464 (clobber (match_scratch:SI 3 "=1"))]
1465 "TARGET_ATOMIC_HARD_LLCS"
1466 {
1467 return "\r mov #-4,%2" "\n"
1468 " and %1,%2" "\n"
1469 " xor %2,%1" "\n"
1470 " add r15,%1" "\n"
1471 " add #-4,%1" "\n"
1472 "0: movli.l @%2,r0" "\n"
1473 " mov.l r0,@-r15" "\n"
1474 " mov.<bw> @%1,r0" "\n"
1475 " not r0,r0" "\n"
1476 " mov.<bw> r0,@%1" "\n"
1477 " mov r0,%0" "\n"
1478 " mov.l @r15+,r0" "\n"
1479 " movco.l r0,@%2" "\n"
1480 " bf 0b";
1481 }
1482 "&& can_create_pseudo_p () && optimize
1483 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1484 [(const_int 0)]
1485 {
1486 emit_insn (gen_atomic_not<mode>_hard (operands[1]));
1487 }
1488 [(set_attr "length" "28")])
1489
1490 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_gusa"
1491 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1492 (FETCHOP:QIHISI
1493 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u"))
1494 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1495 "<fetchop_constraint_1_gusa>")))
1496 (set (mem:QIHISI (match_dup 1))
1497 (unspec:QIHISI
1498 [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
1499 UNSPEC_ATOMIC))
1500 (clobber (reg:SI R0_REG))
1501 (clobber (reg:SI R1_REG))]
1502 "TARGET_ATOMIC_SOFT_GUSA"
1503 {
1504 return "\r mova 1f,r0" "\n"
1505 " mov r15,r1" "\n"
1506 " .align 2" "\n"
1507 " mov #(0f-1f),r15" "\n"
1508 "0: mov.<bwl> @%1,%0" "\n"
1509 " <fetchop_name> %2,%0" "\n"
1510 " mov.<bwl> %0,@%1" "\n"
1511 "1: mov r1,r15";
1512 }
1513 [(set_attr "length" "16")])
1514
1515 ;; Combine pattern for xor (val, -1) / nand (val, -1).
1516 (define_insn "atomic_not_fetch<mode>_soft_gusa"
1517 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1518 (not:QIHISI (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u"))))
1519 (set (mem:QIHISI (match_dup 1))
1520 (unspec:QIHISI [(not:QIHISI (mem:QIHISI (match_dup 1)))] UNSPEC_ATOMIC))
1521 (clobber (reg:SI R0_REG))
1522 (clobber (reg:SI R1_REG))]
1523 "TARGET_ATOMIC_SOFT_GUSA"
1524 {
1525 return "\r mova 1f,r0" "\n"
1526 " mov r15,r1" "\n"
1527 " .align 2" "\n"
1528 " mov #(0f-1f),r15" "\n"
1529 "0: mov.<bwl> @%1,%0" "\n"
1530 " not %0,%0" "\n"
1531 " mov.<bwl> %0,@%1" "\n"
1532 "1: mov r1,r15";
1533 }
1534 [(set_attr "length" "16")])
1535
1536 (define_insn_and_split "atomic_<fetchop_name>_fetch<mode>_soft_tcb"
1537 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1538 (FETCHOP:QIHISI
1539 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
1540 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1541 "<fetchop_constraint_1_tcb>")))
1542 (set (mem:QIHISI (match_dup 1))
1543 (unspec:QIHISI
1544 [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
1545 UNSPEC_ATOMIC))
1546 (clobber (reg:SI R0_REG))
1547 (clobber (reg:SI R1_REG))
1548 (use (match_operand:SI 3 "gbr_displacement"))]
1549 "TARGET_ATOMIC_SOFT_TCB"
1550 {
1551 return "\r mova 1f,r0" "\n"
1552 " mov #(0f-1f),r1" "\n"
1553 " .align 2" "\n"
1554 " mov.l r0,@(%O3,gbr)" "\n"
1555 "0: mov.<bwl> @%1,r0" "\n"
1556 " <fetchop_name> %2,r0" "\n"
1557 " mov.<bwl> r0,@%1" "\n"
1558 "1: mov r0,%0" "\n"
1559 " mov #0,r0" "\n"
1560 " mov.l r0,@(%O3,gbr)";
1561 }
1562 "&& can_create_pseudo_p () && optimize
1563 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1564 [(const_int 0)]
1565 {
1566 emit_insn (gen_atomic_<fetchop_name><mode>_soft_tcb (
1567 operands[1], operands[2], operands[3]));
1568 }
1569 [(set_attr "length" "20")])
1570
1571 ;; Combine pattern for xor (val, -1) / nand (val, -1).
1572 (define_insn_and_split "atomic_not_fetch<mode>_soft_tcb"
1573 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1574 (not:QIHISI (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))))
1575 (set (mem:QIHISI (match_dup 1))
1576 (unspec:QIHISI [(not:QIHISI (mem:QIHISI (match_dup 1)))] UNSPEC_ATOMIC))
1577 (clobber (reg:SI R0_REG))
1578 (clobber (reg:SI R1_REG))
1579 (use (match_operand:SI 2 "gbr_displacement"))]
1580 "TARGET_ATOMIC_SOFT_TCB"
1581 {
1582 return "\r mova 1f,r0" "\n"
1583 " mov #(0f-1f),r1" "\n"
1584 " .align 2" "\n"
1585 " mov.l r0,@(%O2,gbr)" "\n"
1586 "0: mov.<bwl> @%1,r0" "\n"
1587 " not r0,r0" "\n"
1588 " mov.<bwl> r0,@%1" "\n"
1589 "1: mov r0,%0" "\n"
1590 " mov #0,r0" "\n"
1591 " mov.l r0,@(%O2,gbr)";
1592 }
1593 "&& can_create_pseudo_p () && optimize
1594 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1595 [(const_int 0)]
1596 {
1597 emit_insn (gen_atomic_not<mode>_soft_tcb (operands[1], operands[2]));
1598 }
1599 [(set_attr "length" "20")])
1600
1601 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_imask"
1602 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
1603 (FETCHOP:QIHISI
1604 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
1605 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1606 "<fetchop_constraint_1_imask>")))
1607 (set (mem:QIHISI (match_dup 1))
1608 (unspec:QIHISI
1609 [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
1610 UNSPEC_ATOMIC))
1611 (clobber (match_scratch:SI 3 "=&r"))]
1612 "TARGET_ATOMIC_SOFT_IMASK"
1613 {
1614 return "\r stc sr,%0" "\n"
1615 " mov %0,%3" "\n"
1616 " or #0xF0,%0" "\n"
1617 " ldc %0,sr" "\n"
1618 " mov.<bwl> @%1,%0" "\n"
1619 " <fetchop_name> %2,%0" "\n"
1620 " mov.<bwl> %0,@%1" "\n"
1621 " ldc %3,sr";
1622 }
1623 [(set_attr "length" "16")])
1624
1625 ;; Combine pattern for xor (val, -1) / nand (val, -1).
1626 (define_insn "atomic_not_fetch<mode>_soft_imask"
1627 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
1628 (not:QIHISI (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))))
1629 (set (mem:QIHISI (match_dup 1))
1630 (unspec:QIHISI [(not:QIHISI (mem:QIHISI (match_dup 1)))] UNSPEC_ATOMIC))
1631 (clobber (match_scratch:SI 2 "=&r"))]
1632 "TARGET_ATOMIC_SOFT_IMASK"
1633 {
1634 return "\r stc sr,%0" "\n"
1635 " mov %0,%2" "\n"
1636 " or #0xF0,%0" "\n"
1637 " ldc %0,sr" "\n"
1638 " mov.<bwl> @%1,%0" "\n"
1639 " not %0,%0" "\n"
1640 " mov.<bwl> %0,@%1" "\n"
1641 " ldc %2,sr";
1642 }
1643 [(set_attr "length" "16")])
1644
1645 (define_expand "atomic_nand_fetch<mode>"
1646 [(set (match_operand:QIHISI 0 "arith_reg_dest")
1647 (not:QIHISI (and:QIHISI
1648 (match_operand:QIHISI 1 "memory_operand")
1649 (match_operand:QIHISI 2 "atomic_logical_operand_1"))))
1650 (set (match_dup 1)
1651 (unspec:QIHISI
1652 [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))]
1653 UNSPEC_ATOMIC))
1654 (match_operand:SI 3 "const_int_operand")]
1655 "TARGET_ATOMIC_ANY"
1656 {
1657 rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
1658 rtx atomic_insn;
1659
1660 if (TARGET_ATOMIC_HARD_LLCS
1661 || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
1662 atomic_insn = gen_atomic_nand_fetch<mode>_hard (operands[0], addr,
1663 operands[2]);
1664 else if (TARGET_ATOMIC_SOFT_GUSA)
1665 atomic_insn = gen_atomic_nand_fetch<mode>_soft_gusa (operands[0], addr,
1666 operands[2]);
1667 else if (TARGET_ATOMIC_SOFT_TCB)
1668 atomic_insn = gen_atomic_nand_fetch<mode>_soft_tcb (operands[0], addr,
1669 operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
1670 else if (TARGET_ATOMIC_SOFT_IMASK)
1671 atomic_insn = gen_atomic_nand_fetch<mode>_soft_imask (operands[0], addr,
1672 operands[2]);
1673 else
1674 FAIL;
1675
1676 emit_insn (atomic_insn);
1677
1678 if (<MODE>mode == QImode)
1679 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
1680 operands[0]));
1681 else if (<MODE>mode == HImode)
1682 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
1683 operands[0]));
1684 DONE;
1685 })
1686
1687 (define_insn "atomic_nand_fetchsi_hard"
1688 [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
1689 (not:SI (and:SI (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
1690 (match_operand:SI 2 "logical_operand" "rK08"))))
1691 (set (mem:SI (match_dup 1))
1692 (unspec:SI
1693 [(not:SI (and:SI (mem:SI (match_dup 1)) (match_dup 2)))]
1694 UNSPEC_ATOMIC))
1695 (set (reg:SI T_REG) (const_int 1))]
1696 "TARGET_ATOMIC_HARD_LLCS
1697 || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1698 {
1699 return "\r0: movli.l @%1,%0" "\n"
1700 " and %2,%0" "\n"
1701 " not %0,%0" "\n"
1702 " movco.l %0,@%1" "\n"
1703 " bf 0b";
1704 }
1705 [(set_attr "length" "10")])
1706
1707 (define_insn_and_split "atomic_nand_fetch<mode>_hard"
1708 [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1709 (not:QIHI
1710 (and:QIHI (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
1711 (match_operand:QIHI 2 "logical_operand" "rK08"))))
1712 (set (mem:QIHI (match_dup 1))
1713 (unspec:QIHI
1714 [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1)) (match_dup 2)))]
1715 UNSPEC_ATOMIC))
1716 (set (reg:SI T_REG) (const_int 1))
1717 (clobber (reg:SI R0_REG))
1718 (clobber (match_scratch:SI 3 "=&r"))
1719 (clobber (match_scratch:SI 4 "=1"))]
1720 "TARGET_ATOMIC_HARD_LLCS"
1721 {
1722 return "\r mov #-4,%3" "\n"
1723 " and %1,%3" "\n"
1724 " xor %3,%1" "\n"
1725 " add r15,%1" "\n"
1726 " add #-4,%1" "\n"
1727 "0: movli.l @%3,r0" "\n"
1728 " mov.l r0,@-r15" "\n"
1729 " mov.<bw> @%1,r0" "\n"
1730 " and %2,r0" "\n"
1731 " not r0,%0" "\n"
1732 " mov.<bw> %0,@%1" "\n"
1733 " mov.l @r15+,r0" "\n"
1734 " movco.l r0,@%3" "\n"
1735 " bf 0b";
1736 }
1737 "&& can_create_pseudo_p () && optimize
1738 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1739 [(const_int 0)]
1740 {
1741 emit_insn (gen_atomic_nand<mode>_hard (operands[1], operands[2]));
1742 }
1743 [(set_attr "length" "28")])
1744
1745 (define_insn "atomic_nand_fetch<mode>_soft_gusa"
1746 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1747 (not:QIHISI (and:QIHISI
1748 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u"))
1749 (match_operand:QIHISI 2 "arith_reg_operand" "u"))))
1750 (set (mem:QIHISI (match_dup 1))
1751 (unspec:QIHISI
1752 [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
1753 UNSPEC_ATOMIC))
1754 (clobber (reg:SI R0_REG))
1755 (clobber (reg:SI R1_REG))]
1756 "TARGET_ATOMIC_SOFT_GUSA"
1757 {
1758 return "\r mova 1f,r0" "\n"
1759 " .align 2" "\n"
1760 " mov r15,r1" "\n"
1761 " mov #(0f-1f),r15" "\n"
1762 "0: mov.<bwl> @%1,%0" "\n"
1763 " and %2,%0" "\n"
1764 " not %0,%0" "\n"
1765 " mov.<bwl> %0,@%1" "\n"
1766 "1: mov r1,r15";
1767 }
1768 [(set_attr "length" "18")])
1769
1770 (define_insn_and_split "atomic_nand_fetch<mode>_soft_tcb"
1771 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1772 (not:QIHISI (and:QIHISI
1773 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
1774 (match_operand:QIHISI 2 "logical_operand" "rK08"))))
1775 (set (mem:QIHISI (match_dup 1))
1776 (unspec:QIHISI
1777 [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
1778 UNSPEC_ATOMIC))
1779 (clobber (reg:SI R0_REG))
1780 (clobber (reg:SI R1_REG))
1781 (use (match_operand:SI 3 "gbr_displacement"))]
1782 "TARGET_ATOMIC_SOFT_TCB"
1783 {
1784 return "\r mova 1f,r0" "\n"
1785 " mov #(0f-1f),r1" "\n"
1786 " .align 2" "\n"
1787 " mov.l r0,@(%O3,gbr)" "\n"
1788 "0: mov.<bwl> @%1,r0" "\n"
1789 " and %2,r0" "\n"
1790 " not r0,r0" "\n"
1791 " mov r0,%0" "\n"
1792 " mov.<bwl> r0,@%1" "\n"
1793 "1: mov #0,r0" "\n"
1794 " mov.l r0,@(%O3,gbr)";
1795 }
1796 "&& can_create_pseudo_p () && optimize
1797 && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1798 [(const_int 0)]
1799 {
1800 emit_insn (gen_atomic_nand<mode>_soft_tcb (operands[1], operands[2],
1801 operands[3]));
1802 }
1803 [(set_attr "length" "22")])
1804
1805 (define_insn "atomic_nand_fetch<mode>_soft_imask"
1806 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
1807 (not:QIHISI (and:QIHISI
1808 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
1809 (match_operand:QIHISI 2 "logical_operand" "rK08"))))
1810 (set (mem:QIHISI (match_dup 1))
1811 (unspec:QIHISI
1812 [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
1813 UNSPEC_ATOMIC))
1814 (clobber (match_scratch:SI 3 "=&r"))]
1815 "TARGET_ATOMIC_SOFT_IMASK"
1816 {
1817 return "\r stc sr,%0" "\n"
1818 " mov %0,%3" "\n"
1819 " or #0xF0,%0" "\n"
1820 " ldc %0,sr" "\n"
1821 " mov.<bwl> @%1,%0" "\n"
1822 " and %2,%0" "\n"
1823 " not %0,%0" "\n"
1824 " mov.<bwl> %0,@%1" "\n"
1825 " ldc %3,sr";
1826 }
1827 [(set_attr "length" "18")])
1828
1829 ;;------------------------------------------------------------------------------
1830 ;; read - test against zero - or with 0x80 - write - return test result
1831
1832 (define_expand "atomic_test_and_set"
1833 [(match_operand:SI 0 "register_operand" "") ;; bool result output
1834 (match_operand:QI 1 "memory_operand" "") ;; memory
1835 (match_operand:SI 2 "const_int_operand" "")] ;; model
1836 "(TARGET_ATOMIC_ANY || TARGET_ENABLE_TAS) && !TARGET_SHMEDIA"
1837 {
1838 rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
1839
1840 if (TARGET_ENABLE_TAS)
1841 emit_insn (gen_tasb (addr));
1842 else
1843 {
1844 rtx val = gen_int_mode (targetm.atomic_test_and_set_trueval, QImode);
1845 val = force_reg (QImode, val);
1846
1847 if (TARGET_ATOMIC_HARD_LLCS)
1848 emit_insn (gen_atomic_test_and_set_hard (addr, val));
1849 else if (TARGET_ATOMIC_SOFT_GUSA)
1850 emit_insn (gen_atomic_test_and_set_soft_gusa (addr, val));
1851 else if (TARGET_ATOMIC_SOFT_TCB)
1852 emit_insn (gen_atomic_test_and_set_soft_tcb (addr, val,
1853 TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX));
1854 else if (TARGET_ATOMIC_SOFT_IMASK)
1855 emit_insn (gen_atomic_test_and_set_soft_imask (addr, val));
1856 else
1857 FAIL;
1858 }
1859
1860 /* The result of the test op is the inverse of what we are
1861 supposed to return. Thus invert the T bit. The inversion will be
1862 potentially optimized away and integrated into surrounding code. */
1863 emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ()));
1864 DONE;
1865 })
1866
1867 (define_insn "tasb"
1868 [(set (reg:SI T_REG)
1869 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1870 (const_int 0)))
1871 (set (mem:QI (match_dup 0))
1872 (unspec:QI [(const_int 128)] UNSPEC_ATOMIC))]
1873 "TARGET_ENABLE_TAS && !TARGET_SHMEDIA"
1874 "tas.b @%0"
1875 [(set_attr "insn_class" "co_group")])
1876
1877 (define_insn "atomic_test_and_set_soft_gusa"
1878 [(set (reg:SI T_REG)
1879 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "u"))
1880 (const_int 0)))
1881 (set (mem:QI (match_dup 0))
1882 (unspec:QI [(match_operand:QI 1 "register_operand" "u")] UNSPEC_ATOMIC))
1883 (clobber (match_scratch:QI 2 "=&u"))
1884 (clobber (reg:SI R0_REG))
1885 (clobber (reg:SI R1_REG))]
1886 "TARGET_ATOMIC_SOFT_GUSA && !TARGET_ENABLE_TAS"
1887 {
1888 return "\r mova 1f,r0" "\n"
1889 " .align 2" "\n"
1890 " mov r15,r1" "\n"
1891 " mov #(0f-1f),r15" "\n"
1892 "0: mov.b @%0,%2" "\n"
1893 " mov.b %1,@%0" "\n"
1894 "1: mov r1,r15" "\n"
1895 " tst %2,%2";
1896 }
1897 [(set_attr "length" "16")])
1898
1899 (define_insn "atomic_test_and_set_soft_tcb"
1900 [(set (reg:SI T_REG)
1901 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1902 (const_int 0)))
1903 (set (mem:QI (match_dup 0))
1904 (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
1905 (use (match_operand:SI 2 "gbr_displacement"))
1906 (clobber (match_scratch:QI 3 "=&r"))
1907 (clobber (reg:SI R0_REG))
1908 (clobber (reg:SI R1_REG))]
1909 "TARGET_ATOMIC_SOFT_TCB && !TARGET_ENABLE_TAS"
1910 {
1911 return "\r mova 1f,r0" "\n"
1912 " mov #(0f-1f),r1" "\n"
1913 " .align 2" "\n"
1914 " mov.l r0,@(%O2,gbr)" "\n"
1915 "0: mov.b @%0,%3" "\n"
1916 " mov #0,r0" "\n"
1917 " mov.b %1,@%0" "\n"
1918 "1: mov.l r0,@(%O2,gbr)" "\n"
1919 " tst %3,%3";
1920 }
1921 [(set_attr "length" "18")])
1922
1923 (define_insn "atomic_test_and_set_soft_imask"
1924 [(set (reg:SI T_REG)
1925 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1926 (const_int 0)))
1927 (set (mem:QI (match_dup 0))
1928 (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
1929 (clobber (match_scratch:SI 2 "=&r"))
1930 (clobber (reg:SI R0_REG))]
1931 "TARGET_ATOMIC_SOFT_IMASK && !TARGET_ENABLE_TAS"
1932 {
1933 return "\r stc sr,r0" "\n"
1934 " mov r0,%2" "\n"
1935 " or #0xF0,r0" "\n"
1936 " ldc r0,sr" "\n"
1937 " mov.b @%0,r0" "\n"
1938 " mov.b %1,@%0" "\n"
1939 " ldc %2,sr" "\n"
1940 " tst r0,r0";
1941 }
1942 [(set_attr "length" "16")])
1943
1944 (define_insn "atomic_test_and_set_hard"
1945 [(set (reg:SI T_REG)
1946 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1947 (const_int 0)))
1948 (set (mem:QI (match_dup 0))
1949 (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
1950 (clobber (reg:SI R0_REG))
1951 (clobber (match_scratch:SI 2 "=&r"))
1952 (clobber (match_scratch:SI 3 "=&r"))
1953 (clobber (match_scratch:SI 4 "=0"))]
1954 "TARGET_ATOMIC_HARD_LLCS && !TARGET_ENABLE_TAS"
1955 {
1956 return "\r mov #-4,%2" "\n"
1957 " and %0,%2" "\n"
1958 " xor %2,%0" "\n"
1959 " add r15,%0" "\n"
1960 " add #-4,%0" "\n"
1961 "0: movli.l @%2,r0" "\n"
1962 " mov.l r0,@-r15" "\n"
1963 " mov.b @%0,%3" "\n"
1964 " mov.b %1,@%0" "\n"
1965 " mov.l @r15+,r0" "\n"
1966 " movco.l r0,@%2" "\n"
1967 " bf 0b" "\n"
1968 " tst %3,%3";
1969 }
1970 [(set_attr "length" "26")])
1971