]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/sh/sync.md
re PR target/64659 ([SH] Immedate values not used for atomic ops)
[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 "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 [(set_attr "length" "10")])
675
676 (define_insn "atomic_fetch_<fetchop_name><mode>_hard"
677 [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
678 (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
679 (set (mem:QIHI (match_dup 1))
680 (unspec:QIHI
681 [(FETCHOP:QIHI (mem:QIHI (match_dup 1))
682 (match_operand:QIHI 2 "<fetchop_predicate_1>"
683 "<fetchop_constraint_1_llcs>"))]
684 UNSPEC_ATOMIC))
685 (set (reg:SI T_REG) (const_int 1))
686 (clobber (reg:SI R0_REG))
687 (clobber (match_scratch:SI 3 "=&r"))
688 (clobber (match_scratch:SI 4 "=1"))]
689 "TARGET_ATOMIC_HARD_LLCS"
690 {
691 return "\r mov #-4,%3" "\n"
692 " and %1,%3" "\n"
693 " xor %3,%1" "\n"
694 " add r15,%1" "\n"
695 " add #-4,%1" "\n"
696 "0: movli.l @%3,r0" "\n"
697 " mov.l r0,@-r15" "\n"
698 " mov.<bw> @%1,r0" "\n"
699 " mov r0,%0" "\n"
700 " <fetchop_name> %2,r0" "\n"
701 " mov.<bw> r0,@%1" "\n"
702 " mov.l @r15+,r0" "\n"
703 " movco.l r0,@%3" "\n"
704 " bf 0b";
705 }
706 [(set_attr "length" "28")])
707
708 (define_insn "atomic_fetch_<fetchop_name><mode>_soft_gusa"
709 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
710 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u")))
711 (set (mem:QIHISI (match_dup 1))
712 (unspec:QIHISI
713 [(FETCHOP:QIHISI
714 (mem:QIHISI (match_dup 1))
715 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
716 "<fetchop_constraint_1_gusa>"))]
717 UNSPEC_ATOMIC))
718 (clobber (match_scratch:QIHISI 3 "=&u"))
719 (clobber (reg:SI R0_REG))
720 (clobber (reg:SI R1_REG))]
721 "TARGET_ATOMIC_SOFT_GUSA"
722 {
723 return "\r mova 1f,r0" "\n"
724 " .align 2" "\n"
725 " mov r15,r1" "\n"
726 " mov #(0f-1f),r15" "\n"
727 "0: mov.<bwl> @%1,%0" "\n"
728 " mov %0,%3" "\n"
729 " <fetchop_name> %2,%3" "\n"
730 " mov.<bwl> %3,@%1" "\n"
731 "1: mov r1,r15";
732 }
733 [(set_attr "length" "18")])
734
735 (define_insn "atomic_fetch_<fetchop_name><mode>_soft_tcb"
736 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
737 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
738 (set (mem:QIHISI (match_dup 1))
739 (unspec:QIHISI
740 [(FETCHOP:QIHISI
741 (mem:QIHISI (match_dup 1))
742 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
743 "<fetchop_constraint_1_tcb>"))]
744 UNSPEC_ATOMIC))
745 (use (match_operand:SI 3 "gbr_displacement"))
746 (clobber (reg:SI R0_REG))
747 (clobber (reg:SI R1_REG))]
748 "TARGET_ATOMIC_SOFT_TCB"
749 {
750 return "\r mova 1f,r0" "\n"
751 " .align 2" "\n"
752 " mov #(0f-1f),r1" "\n"
753 " mov.l r0,@(%O3,gbr)" "\n"
754 "0: mov.<bwl> @%1,r0" "\n"
755 " mov r0,%0" "\n"
756 " <fetchop_name> %2,r0" "\n"
757 " mov.<bwl> r0,@%1" "\n"
758 "1: mov #0,r0" "\n"
759 " mov.l r0,@(%O3,gbr)";
760 }
761 [(set_attr "length" "20")])
762
763 (define_insn "atomic_fetch_<fetchop_name><mode>_soft_imask"
764 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
765 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
766 (set (mem:QIHISI (match_dup 1))
767 (unspec:QIHISI
768 [(FETCHOP:QIHISI
769 (mem:QIHISI (match_dup 1))
770 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
771 "<fetchop_constraint_1_imask>"))]
772 UNSPEC_ATOMIC))
773 (clobber (reg:SI R0_REG))
774 (clobber (match_scratch:QIHISI 3 "=&r"))]
775 "TARGET_ATOMIC_SOFT_IMASK"
776 {
777 return "\r stc sr,r0" "\n"
778 " mov r0,%3" "\n"
779 " or #0xF0,r0" "\n"
780 " ldc r0,sr" "\n"
781 " mov.<bwl> @%1,r0" "\n"
782 " mov r0,%0" "\n"
783 " <fetchop_name> %2,r0" "\n"
784 " mov.<bwl> r0,@%1" "\n"
785 " ldc %3,sr";
786 }
787 [(set_attr "length" "18")])
788
789 (define_expand "atomic_fetch_nand<mode>"
790 [(set (match_operand:QIHISI 0 "arith_reg_dest")
791 (match_operand:QIHISI 1 "memory_operand"))
792 (set (match_dup 1)
793 (unspec:QIHISI
794 [(not:QIHISI (and:QIHISI (match_dup 1)
795 (match_operand:QIHISI 2 "atomic_logical_operand_1")))]
796 UNSPEC_ATOMIC))
797 (match_operand:SI 3 "const_int_operand")]
798 "TARGET_ATOMIC_ANY"
799 {
800 rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
801 rtx atomic_insn;
802
803 if (TARGET_ATOMIC_HARD_LLCS
804 || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
805 atomic_insn = gen_atomic_fetch_nand<mode>_hard (operands[0], addr,
806 operands[2]);
807 else if (TARGET_ATOMIC_SOFT_GUSA)
808 atomic_insn = gen_atomic_fetch_nand<mode>_soft_gusa (operands[0], addr,
809 operands[2]);
810 else if (TARGET_ATOMIC_SOFT_TCB)
811 atomic_insn = gen_atomic_fetch_nand<mode>_soft_tcb (operands[0], addr,
812 operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
813 else if (TARGET_ATOMIC_SOFT_IMASK)
814 atomic_insn = gen_atomic_fetch_nand<mode>_soft_imask (operands[0], addr,
815 operands[2]);
816 else
817 FAIL;
818
819 emit_insn (atomic_insn);
820
821 if (<MODE>mode == QImode)
822 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
823 operands[0]));
824 else if (<MODE>mode == HImode)
825 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
826 operands[0]));
827 DONE;
828 })
829
830 (define_insn "atomic_fetch_nandsi_hard"
831 [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
832 (mem:SI (match_operand:SI 1 "arith_reg_operand" "r")))
833 (set (mem:SI (match_dup 1))
834 (unspec:SI
835 [(not:SI (and:SI (mem:SI (match_dup 1))
836 (match_operand:SI 2 "logical_operand" "rK08")))]
837 UNSPEC_ATOMIC))
838 (set (reg:SI T_REG) (const_int 1))
839 (clobber (reg:SI R0_REG))]
840 "TARGET_ATOMIC_HARD_LLCS
841 || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
842 {
843 return "\r0: movli.l @%1,r0" "\n"
844 " mov r0,%0" "\n"
845 " and %2,r0" "\n"
846 " not r0,r0" "\n"
847 " movco.l r0,@%1" "\n"
848 " bf 0b";
849 }
850 [(set_attr "length" "12")])
851
852 (define_insn "atomic_fetch_nand<mode>_hard"
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 [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1))
858 (match_operand:QIHI 2 "logical_operand" "rK08")))]
859 UNSPEC_ATOMIC))
860 (set (reg:SI T_REG) (const_int 1))
861 (clobber (reg:SI R0_REG))
862 (clobber (match_scratch:SI 3 "=&r"))
863 (clobber (match_scratch:SI 4 "=1"))]
864 "TARGET_ATOMIC_HARD_LLCS"
865 {
866 return "\r mov #-4,%3" "\n"
867 " and %1,%3" "\n"
868 " xor %3,%1" "\n"
869 " add r15,%1" "\n"
870 " add #-4,%1" "\n"
871 "0: movli.l @%3,r0" "\n"
872 " mov.l r0,@-r15" "\n"
873 " mov.<bw> @%1,r0" "\n"
874 " mov r0,%0" "\n"
875 " and %2,r0" "\n"
876 " not r0,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" "30")])
883
884 (define_insn "atomic_fetch_nand<mode>_soft_gusa"
885 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
886 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u")))
887 (set (mem:QIHISI (match_dup 1))
888 (unspec:QIHISI
889 [(not:QIHISI
890 (and:QIHISI (mem:QIHISI (match_dup 1))
891 (match_operand:QIHISI 2 "arith_reg_operand" "u")))]
892 UNSPEC_ATOMIC))
893 (clobber (match_scratch:QIHISI 3 "=&u"))
894 (clobber (reg:SI R0_REG))
895 (clobber (reg:SI R1_REG))]
896 "TARGET_ATOMIC_SOFT_GUSA"
897 {
898 return "\r mova 1f,r0" "\n"
899 " mov r15,r1" "\n"
900 " .align 2" "\n"
901 " mov #(0f-1f),r15" "\n"
902 "0: mov.<bwl> @%1,%0" "\n"
903 " mov %2,%3" "\n"
904 " and %0,%3" "\n"
905 " not %3,%3" "\n"
906 " mov.<bwl> %3,@%1" "\n"
907 "1: mov r1,r15";
908 }
909 [(set_attr "length" "20")])
910
911 (define_insn "atomic_fetch_nand<mode>_soft_tcb"
912 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
913 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
914 (set (mem:QIHISI (match_dup 1))
915 (unspec:QIHISI
916 [(not:QIHISI
917 (and:QIHISI (mem:QIHISI (match_dup 1))
918 (match_operand:QIHISI 2 "logical_operand" "rK08")))]
919 UNSPEC_ATOMIC))
920 (use (match_operand:SI 3 "gbr_displacement"))
921 (clobber (reg:SI R0_REG))
922 (clobber (reg:SI R1_REG))]
923 "TARGET_ATOMIC_SOFT_TCB"
924 {
925 return "\r mova 1f,r0" "\n"
926 " mov #(0f-1f),r1" "\n"
927 " .align 2" "\n"
928 " mov.l r0,@(%O3,gbr)" "\n"
929 "0: mov.<bwl> @%1,r0" "\n"
930 " mov r0,%0" "\n"
931 " and %2,r0" "\n"
932 " not r0,r0" "\n"
933 " mov.<bwl> r0,@%1" "\n"
934 "1: mov #0,r0" "\n"
935 " mov.l r0,@(%O3,gbr)";
936 }
937 [(set_attr "length" "22")])
938
939 (define_insn "atomic_fetch_nand<mode>_soft_imask"
940 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
941 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r")))
942 (set (mem:QIHISI (match_dup 1))
943 (unspec:QIHISI
944 [(not:QIHISI
945 (and:QIHISI (mem:QIHISI (match_dup 1))
946 (match_operand:QIHISI 2 "logical_operand" "rK08")))]
947 UNSPEC_ATOMIC))
948 (clobber (reg:SI R0_REG))
949 (clobber (match_scratch:SI 3 "=&r"))]
950 "TARGET_ATOMIC_SOFT_IMASK"
951 {
952 return "\r stc sr,r0" "\n"
953 " mov r0,%3" "\n"
954 " or #0xF0,r0" "\n"
955 " ldc r0,sr" "\n"
956 " mov.<bwl> @%1,r0" "\n"
957 " mov r0,%0" "\n"
958 " and %2,r0" "\n"
959 " not r0,r0" "\n"
960 " mov.<bwl> r0,@%1" "\n"
961 " ldc %3,sr";
962 }
963 [(set_attr "length" "20")])
964
965 ;;------------------------------------------------------------------------------
966 ;; read - add|sub|or|and|xor|nand - write - return new value
967
968 (define_expand "atomic_<fetchop_name>_fetch<mode>"
969 [(set (match_operand:QIHISI 0 "arith_reg_dest")
970 (FETCHOP:QIHISI
971 (match_operand:QIHISI 1 "memory_operand")
972 (match_operand:QIHISI 2 "<fetchop_predicate_1>")))
973 (set (match_dup 1)
974 (unspec:QIHISI
975 [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))]
976 UNSPEC_ATOMIC))
977 (match_operand:SI 3 "const_int_operand" "")]
978 "TARGET_ATOMIC_ANY"
979 {
980 rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
981 rtx atomic_insn;
982
983 if (TARGET_ATOMIC_HARD_LLCS
984 || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
985 atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_hard (operands[0], addr,
986 operands[2]);
987 else if (TARGET_ATOMIC_SOFT_GUSA)
988 atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_gusa (operands[0],
989 addr, operands[2]);
990 else if (TARGET_ATOMIC_SOFT_TCB)
991 atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_tcb (operands[0],
992 addr, operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
993 else if (TARGET_ATOMIC_SOFT_IMASK)
994 atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_imask (operands[0],
995 addr, operands[2]);
996 else
997 FAIL;
998
999 emit_insn (atomic_insn);
1000
1001 if (<MODE>mode == QImode)
1002 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
1003 operands[0]));
1004 else if (<MODE>mode == HImode)
1005 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
1006 operands[0]));
1007 DONE;
1008 })
1009
1010 (define_insn "atomic_<fetchop_name>_fetchsi_hard"
1011 [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
1012 (FETCHOP:SI
1013 (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
1014 (match_operand:SI 2 "<fetchop_predicate_1>"
1015 "<fetchop_constraint_1_llcs>")))
1016 (set (mem:SI (match_dup 1))
1017 (unspec:SI
1018 [(FETCHOP:SI (mem:SI (match_dup 1)) (match_dup 2))]
1019 UNSPEC_ATOMIC))
1020 (set (reg:SI T_REG) (const_int 1))]
1021 "TARGET_ATOMIC_HARD_LLCS
1022 || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1023 {
1024 return "\r0: movli.l @%1,%0" "\n"
1025 " <fetchop_name> %2,%0" "\n"
1026 " movco.l %0,@%1" "\n"
1027 " bf 0b";
1028 }
1029 [(set_attr "length" "8")])
1030
1031 (define_insn "atomic_<fetchop_name>_fetch<mode>_hard"
1032 [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1033 (FETCHOP:QIHI
1034 (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
1035 (match_operand:QIHI 2 "<fetchop_predicate_1>"
1036 "<fetchop_constraint_1_llcs>")))
1037 (set (mem:QIHI (match_dup 1))
1038 (unspec:QIHI
1039 [(FETCHOP:QIHI (mem:QIHI (match_dup 1)) (match_dup 2))]
1040 UNSPEC_ATOMIC))
1041 (set (reg:SI T_REG) (const_int 1))
1042 (clobber (reg:SI R0_REG))
1043 (clobber (match_scratch:SI 3 "=&r"))
1044 (clobber (match_scratch:SI 4 "=1"))]
1045 "TARGET_ATOMIC_HARD_LLCS"
1046 {
1047 return "\r mov #-4,%3" "\n"
1048 " and %1,%3" "\n"
1049 " xor %3,%1" "\n"
1050 " add r15,%1" "\n"
1051 " add #-4,%1" "\n"
1052 "0: movli.l @%3,r0" "\n"
1053 " mov.l r0,@-r15" "\n"
1054 " mov.<bw> @%1,r0" "\n"
1055 " <fetchop_name> %2,r0" "\n"
1056 " mov.<bw> r0,@%1" "\n"
1057 " mov r0,%0" "\n"
1058 " mov.l @r15+,r0" "\n"
1059 " movco.l r0,@%3" "\n"
1060 " bf 0b";
1061 }
1062 [(set_attr "length" "28")])
1063
1064 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_gusa"
1065 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1066 (FETCHOP:QIHISI
1067 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u"))
1068 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1069 "<fetchop_constraint_1_gusa>")))
1070 (set (mem:QIHISI (match_dup 1))
1071 (unspec:QIHISI
1072 [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
1073 UNSPEC_ATOMIC))
1074 (clobber (reg:SI R0_REG))
1075 (clobber (reg:SI R1_REG))]
1076 "TARGET_ATOMIC_SOFT_GUSA"
1077 {
1078 return "\r mova 1f,r0" "\n"
1079 " mov r15,r1" "\n"
1080 " .align 2" "\n"
1081 " mov #(0f-1f),r15" "\n"
1082 "0: mov.<bwl> @%1,%0" "\n"
1083 " <fetchop_name> %2,%0" "\n"
1084 " mov.<bwl> %0,@%1" "\n"
1085 "1: mov r1,r15";
1086 }
1087 [(set_attr "length" "16")])
1088
1089 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_tcb"
1090 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1091 (FETCHOP:QIHISI
1092 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
1093 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1094 "<fetchop_constraint_1_tcb>")))
1095 (set (mem:QIHISI (match_dup 1))
1096 (unspec:QIHISI
1097 [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
1098 UNSPEC_ATOMIC))
1099 (clobber (reg:SI R0_REG))
1100 (clobber (reg:SI R1_REG))
1101 (use (match_operand:SI 3 "gbr_displacement"))]
1102 "TARGET_ATOMIC_SOFT_TCB"
1103 {
1104 return "\r mova 1f,r0" "\n"
1105 " mov #(0f-1f),r1" "\n"
1106 " .align 2" "\n"
1107 " mov.l r0,@(%O3,gbr)" "\n"
1108 "0: mov.<bwl> @%1,r0" "\n"
1109 " <fetchop_name> %2,r0" "\n"
1110 " mov.<bwl> r0,@%1" "\n"
1111 "1: mov r0,%0" "\n"
1112 " mov #0,r0" "\n"
1113 " mov.l r0,@(%O3,gbr)";
1114 }
1115 [(set_attr "length" "20")])
1116
1117 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_imask"
1118 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
1119 (FETCHOP:QIHISI
1120 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
1121 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1122 "<fetchop_constraint_1_imask>")))
1123 (set (mem:QIHISI (match_dup 1))
1124 (unspec:QIHISI
1125 [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
1126 UNSPEC_ATOMIC))
1127 (clobber (match_scratch:SI 3 "=&r"))]
1128 "TARGET_ATOMIC_SOFT_IMASK"
1129 {
1130 return "\r stc sr,%0" "\n"
1131 " mov %0,%3" "\n"
1132 " or #0xF0,%0" "\n"
1133 " ldc %0,sr" "\n"
1134 " mov.<bwl> @%1,%0" "\n"
1135 " <fetchop_name> %2,%0" "\n"
1136 " mov.<bwl> %0,@%1" "\n"
1137 " ldc %3,sr";
1138 }
1139 [(set_attr "length" "16")])
1140
1141 (define_expand "atomic_nand_fetch<mode>"
1142 [(set (match_operand:QIHISI 0 "arith_reg_dest")
1143 (not:QIHISI (and:QIHISI
1144 (match_operand:QIHISI 1 "memory_operand")
1145 (match_operand:QIHISI 2 "atomic_logical_operand_1"))))
1146 (set (match_dup 1)
1147 (unspec:QIHISI
1148 [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))]
1149 UNSPEC_ATOMIC))
1150 (match_operand:SI 3 "const_int_operand")]
1151 "TARGET_ATOMIC_ANY"
1152 {
1153 rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
1154 rtx atomic_insn;
1155
1156 if (TARGET_ATOMIC_HARD_LLCS
1157 || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
1158 atomic_insn = gen_atomic_nand_fetch<mode>_hard (operands[0], addr,
1159 operands[2]);
1160 else if (TARGET_ATOMIC_SOFT_GUSA)
1161 atomic_insn = gen_atomic_nand_fetch<mode>_soft_gusa (operands[0], addr,
1162 operands[2]);
1163 else if (TARGET_ATOMIC_SOFT_TCB)
1164 atomic_insn = gen_atomic_nand_fetch<mode>_soft_tcb (operands[0], addr,
1165 operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
1166 else if (TARGET_ATOMIC_SOFT_IMASK)
1167 atomic_insn = gen_atomic_nand_fetch<mode>_soft_imask (operands[0], addr,
1168 operands[2]);
1169 else
1170 FAIL;
1171
1172 emit_insn (atomic_insn);
1173
1174 if (<MODE>mode == QImode)
1175 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
1176 operands[0]));
1177 else if (<MODE>mode == HImode)
1178 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
1179 operands[0]));
1180 DONE;
1181 })
1182
1183 (define_insn "atomic_nand_fetchsi_hard"
1184 [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
1185 (not:SI (and:SI (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
1186 (match_operand:SI 2 "logical_operand" "rK08"))))
1187 (set (mem:SI (match_dup 1))
1188 (unspec:SI
1189 [(not:SI (and:SI (mem:SI (match_dup 1)) (match_dup 2)))]
1190 UNSPEC_ATOMIC))
1191 (set (reg:SI T_REG) (const_int 1))]
1192 "TARGET_ATOMIC_HARD_LLCS
1193 || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1194 {
1195 return "\r0: movli.l @%1,%0" "\n"
1196 " and %2,%0" "\n"
1197 " not %0,%0" "\n"
1198 " movco.l %0,@%1" "\n"
1199 " bf 0b";
1200 }
1201 [(set_attr "length" "10")])
1202
1203 (define_insn "atomic_nand_fetch<mode>_hard"
1204 [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1205 (not:QIHI
1206 (and:QIHI (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
1207 (match_operand:QIHI 2 "logical_operand" "rK08"))))
1208 (set (mem:QIHI (match_dup 1))
1209 (unspec:QIHI
1210 [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1)) (match_dup 2)))]
1211 UNSPEC_ATOMIC))
1212 (set (reg:SI T_REG) (const_int 1))
1213 (clobber (reg:SI R0_REG))
1214 (clobber (match_scratch:SI 3 "=&r"))
1215 (clobber (match_scratch:SI 4 "=1"))]
1216 "TARGET_ATOMIC_HARD_LLCS"
1217 {
1218 return "\r mov #-4,%3" "\n"
1219 " and %1,%3" "\n"
1220 " xor %3,%1" "\n"
1221 " add r15,%1" "\n"
1222 " add #-4,%1" "\n"
1223 "0: movli.l @%3,r0" "\n"
1224 " mov.l r0,@-r15" "\n"
1225 " mov.<bw> @%1,r0" "\n"
1226 " and %2,r0" "\n"
1227 " not r0,%0" "\n"
1228 " mov.<bw> %0,@%1" "\n"
1229 " mov.l @r15+,r0" "\n"
1230 " movco.l r0,@%3" "\n"
1231 " bf 0b";
1232 }
1233 [(set_attr "length" "28")])
1234
1235 (define_insn "atomic_nand_fetch<mode>_soft_gusa"
1236 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1237 (not:QIHISI (and:QIHISI
1238 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "u"))
1239 (match_operand:QIHISI 2 "arith_reg_operand" "u"))))
1240 (set (mem:QIHISI (match_dup 1))
1241 (unspec:QIHISI
1242 [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
1243 UNSPEC_ATOMIC))
1244 (clobber (reg:SI R0_REG))
1245 (clobber (reg:SI R1_REG))]
1246 "TARGET_ATOMIC_SOFT_GUSA"
1247 {
1248 return "\r mova 1f,r0" "\n"
1249 " .align 2" "\n"
1250 " mov r15,r1" "\n"
1251 " mov #(0f-1f),r15" "\n"
1252 "0: mov.<bwl> @%1,%0" "\n"
1253 " and %2,%0" "\n"
1254 " not %0,%0" "\n"
1255 " mov.<bwl> %0,@%1" "\n"
1256 "1: mov r1,r15";
1257 }
1258 [(set_attr "length" "18")])
1259
1260 (define_insn "atomic_nand_fetch<mode>_soft_tcb"
1261 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1262 (not:QIHISI (and:QIHISI
1263 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
1264 (match_operand:QIHISI 2 "logical_operand" "rK08"))))
1265 (set (mem:QIHISI (match_dup 1))
1266 (unspec:QIHISI
1267 [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
1268 UNSPEC_ATOMIC))
1269 (clobber (reg:SI R0_REG))
1270 (clobber (reg:SI R1_REG))
1271 (use (match_operand:SI 3 "gbr_displacement"))]
1272 "TARGET_ATOMIC_SOFT_TCB"
1273 {
1274 return "\r mova 1f,r0" "\n"
1275 " mov #(0f-1f),r1" "\n"
1276 " .align 2" "\n"
1277 " mov.l r0,@(%O3,gbr)" "\n"
1278 "0: mov.<bwl> @%1,r0" "\n"
1279 " and %2,r0" "\n"
1280 " not r0,r0" "\n"
1281 " mov r0,%0" "\n"
1282 " mov.<bwl> r0,@%1" "\n"
1283 "1: mov #0,r0" "\n"
1284 " mov.l r0,@(%O3,gbr)";
1285 }
1286 [(set_attr "length" "22")])
1287
1288 (define_insn "atomic_nand_fetch<mode>_soft_imask"
1289 [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
1290 (not:QIHISI (and:QIHISI
1291 (mem:QIHISI (match_operand:SI 1 "arith_reg_operand" "r"))
1292 (match_operand:QIHISI 2 "logical_operand" "rK08"))))
1293 (set (mem:QIHISI (match_dup 1))
1294 (unspec:QIHISI
1295 [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
1296 UNSPEC_ATOMIC))
1297 (clobber (match_scratch:SI 3 "=&r"))]
1298 "TARGET_ATOMIC_SOFT_IMASK"
1299 {
1300 return "\r stc sr,%0" "\n"
1301 " mov %0,%3" "\n"
1302 " or #0xF0,%0" "\n"
1303 " ldc %0,sr" "\n"
1304 " mov.<bwl> @%1,%0" "\n"
1305 " and %2,%0" "\n"
1306 " not %0,%0" "\n"
1307 " mov.<bwl> %0,@%1" "\n"
1308 " ldc %3,sr";
1309 }
1310 [(set_attr "length" "18")])
1311
1312 ;;------------------------------------------------------------------------------
1313 ;; read - test against zero - or with 0x80 - write - return test result
1314
1315 (define_expand "atomic_test_and_set"
1316 [(match_operand:SI 0 "register_operand" "") ;; bool result output
1317 (match_operand:QI 1 "memory_operand" "") ;; memory
1318 (match_operand:SI 2 "const_int_operand" "")] ;; model
1319 "(TARGET_ATOMIC_ANY || TARGET_ENABLE_TAS) && !TARGET_SHMEDIA"
1320 {
1321 rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
1322
1323 if (TARGET_ENABLE_TAS)
1324 emit_insn (gen_tasb (addr));
1325 else
1326 {
1327 rtx val = gen_int_mode (targetm.atomic_test_and_set_trueval, QImode);
1328 val = force_reg (QImode, val);
1329
1330 if (TARGET_ATOMIC_HARD_LLCS)
1331 emit_insn (gen_atomic_test_and_set_hard (addr, val));
1332 else if (TARGET_ATOMIC_SOFT_GUSA)
1333 emit_insn (gen_atomic_test_and_set_soft_gusa (addr, val));
1334 else if (TARGET_ATOMIC_SOFT_TCB)
1335 emit_insn (gen_atomic_test_and_set_soft_tcb (addr, val,
1336 TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX));
1337 else if (TARGET_ATOMIC_SOFT_IMASK)
1338 emit_insn (gen_atomic_test_and_set_soft_imask (addr, val));
1339 else
1340 FAIL;
1341 }
1342
1343 /* The result of the test op is the inverse of what we are
1344 supposed to return. Thus invert the T bit. The inversion will be
1345 potentially optimized away and integrated into surrounding code. */
1346 emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ()));
1347 DONE;
1348 })
1349
1350 (define_insn "tasb"
1351 [(set (reg:SI T_REG)
1352 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1353 (const_int 0)))
1354 (set (mem:QI (match_dup 0))
1355 (unspec:QI [(const_int 128)] UNSPEC_ATOMIC))]
1356 "TARGET_ENABLE_TAS && !TARGET_SHMEDIA"
1357 "tas.b @%0"
1358 [(set_attr "insn_class" "co_group")])
1359
1360 (define_insn "atomic_test_and_set_soft_gusa"
1361 [(set (reg:SI T_REG)
1362 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "u"))
1363 (const_int 0)))
1364 (set (mem:QI (match_dup 0))
1365 (unspec:QI [(match_operand:QI 1 "register_operand" "u")] UNSPEC_ATOMIC))
1366 (clobber (match_scratch:QI 2 "=&u"))
1367 (clobber (reg:SI R0_REG))
1368 (clobber (reg:SI R1_REG))]
1369 "TARGET_ATOMIC_SOFT_GUSA && !TARGET_ENABLE_TAS"
1370 {
1371 return "\r mova 1f,r0" "\n"
1372 " .align 2" "\n"
1373 " mov r15,r1" "\n"
1374 " mov #(0f-1f),r15" "\n"
1375 "0: mov.b @%0,%2" "\n"
1376 " mov.b %1,@%0" "\n"
1377 "1: mov r1,r15" "\n"
1378 " tst %2,%2";
1379 }
1380 [(set_attr "length" "16")])
1381
1382 (define_insn "atomic_test_and_set_soft_tcb"
1383 [(set (reg:SI T_REG)
1384 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1385 (const_int 0)))
1386 (set (mem:QI (match_dup 0))
1387 (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
1388 (use (match_operand:SI 2 "gbr_displacement"))
1389 (clobber (match_scratch:QI 3 "=&r"))
1390 (clobber (reg:SI R0_REG))
1391 (clobber (reg:SI R1_REG))]
1392 "TARGET_ATOMIC_SOFT_TCB && !TARGET_ENABLE_TAS"
1393 {
1394 return "\r mova 1f,r0" "\n"
1395 " mov #(0f-1f),r1" "\n"
1396 " .align 2" "\n"
1397 " mov.l r0,@(%O2,gbr)" "\n"
1398 "0: mov.b @%0,%3" "\n"
1399 " mov #0,r0" "\n"
1400 " mov.b %1,@%0" "\n"
1401 "1: mov.l r0,@(%O2,gbr)" "\n"
1402 " tst %3,%3";
1403 }
1404 [(set_attr "length" "18")])
1405
1406 (define_insn "atomic_test_and_set_soft_imask"
1407 [(set (reg:SI T_REG)
1408 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1409 (const_int 0)))
1410 (set (mem:QI (match_dup 0))
1411 (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
1412 (clobber (match_scratch:SI 2 "=&r"))
1413 (clobber (reg:SI R0_REG))]
1414 "TARGET_ATOMIC_SOFT_IMASK && !TARGET_ENABLE_TAS"
1415 {
1416 return "\r stc sr,r0" "\n"
1417 " mov r0,%2" "\n"
1418 " or #0xF0,r0" "\n"
1419 " ldc r0,sr" "\n"
1420 " mov.b @%0,r0" "\n"
1421 " mov.b %1,@%0" "\n"
1422 " ldc %2,sr" "\n"
1423 " tst r0,r0";
1424 }
1425 [(set_attr "length" "16")])
1426
1427 (define_insn "atomic_test_and_set_hard"
1428 [(set (reg:SI T_REG)
1429 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1430 (const_int 0)))
1431 (set (mem:QI (match_dup 0))
1432 (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
1433 (clobber (reg:SI R0_REG))
1434 (clobber (match_scratch:SI 2 "=&r"))
1435 (clobber (match_scratch:SI 3 "=&r"))
1436 (clobber (match_scratch:SI 4 "=0"))]
1437 "TARGET_ATOMIC_HARD_LLCS && !TARGET_ENABLE_TAS"
1438 {
1439 return "\r mov #-4,%2" "\n"
1440 " and %0,%2" "\n"
1441 " xor %2,%0" "\n"
1442 " add r15,%0" "\n"
1443 " add #-4,%0" "\n"
1444 "0: movli.l @%2,r0" "\n"
1445 " mov.l r0,@-r15" "\n"
1446 " mov.b @%0,%3" "\n"
1447 " mov.b %1,@%0" "\n"
1448 " mov.l @r15+,r0" "\n"
1449 " movco.l r0,@%2" "\n"
1450 " bf 0b" "\n"
1451 " tst %3,%3";
1452 }
1453 [(set_attr "length" "26")])
1454