2013-01-08 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / config / sh / sync.md
blob6cd982c79b1eebe5d36efc8753480568374bf06a
1 ;; GCC machine description for SH synchronization instructions.
2 ;; Copyright (C) 2011, 2012
3 ;; Free Software Foundation, Inc.
4 ;;
5 ;; This file is part of GCC.
6 ;;
7 ;; GCC is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation; either version 3, or (at your option)
10 ;; any later version.
12 ;; GCC is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GCC; see the file COPYING3.  If not see
19 ;; <http://www.gnu.org/licenses/>.
22 ;; Atomic integer operations for the Renesas / SuperH SH CPUs.
24 ;; On SH CPUs atomic integer operations can be done either in 'software' or
25 ;; in 'hardware' in various styles.  True hardware support was introduced
26 ;; with the SH4A.  Some SH2A dual-core models (e.g. SH7205) also come with
27 ;; 'semaphore' hardware registers, but these are currently unsupported.
28 ;; All SH CPUs support the 'tas.b' instruction, which can be optionally used
29 ;; to implement the 'atomic_test_and_set' builtin.
30 ;; The following atomic options and models are supported.
32 ;; tas.b atomic_test_and_set (-mtas)
34 ;; Depending on the particular hardware configuration, usage of the 'tas.b'
35 ;; instruction might be undesired or even unsafe.  Thus, it has to be
36 ;; enabled by the user explicitly.  If it is not enabled, the
37 ;; 'atomic_test_and_set' builtin is implemented either with hardware or with
38 ;; software atomics, depending on which is enabled.  It is also possible to
39 ;; enable the 'tas.b' instruction only, without enabling support for the 
40 ;; other atomic operations.
43 ;; Hardware Atomics (-matomic-model=hard-llcs; SH4A only)
45 ;; Hardware atomics implement all atomic operations using the 'movli.l' and
46 ;; 'movco.l' instructions that are availble on SH4A.  On multi-core hardware
47 ;; configurations hardware atomics is the only safe mode.
48 ;; However, it can also be safely used on single-core configurations.
49 ;; Since these instructions operate on SImode memory only, QImode and HImode
50 ;; have to be emulated with SImode and subreg masking, which results in
51 ;; larger code.
54 ;; gUSA Software Atomics (-matomic-model=soft-gusa; SH3*, SH4* only)
56 ;; On single-core systems there can only be one execution context running
57 ;; at a given point in time.  This allows the usage of rewindable atomic
58 ;; sequences, which effectively emulate locked-load / conditional-store
59 ;; operations.  This requires complementary support in the interrupt / 
60 ;; exception handling code (e.g. kernel) and does not work safely on multi-
61 ;; core configurations.
63 ;; When an execution context is interrupted while it is an atomic
64 ;; sequence, the interrupted context's PC is rewound to the beginning of
65 ;; the atomic sequence by the interrupt / exception handling code, before
66 ;; transferring control to another execution context.  This is done by
67 ;; something like...
69 ;;      if (interrupted_context_in_atomic_sequence
70 ;;          && interrupted_pc < atomic_exitpoint)
71 ;;        interrupted_pc = atomic_entrypoint;
73 ;; This method is also known as gUSA ("g" User Space Atomicity) and the
74 ;; Linux kernel for SH3/SH4 implements support for such software atomic
75 ;; sequences.  It can also be implemented in freestanding environments.
77 ;; For this the following atomic sequence ABI is used.
79 ;; r15 >= 0:    Execution context is not in an atomic sequence.
81 ;; r15  < 0:    Execution context is in an atomic sequence and r15
82 ;;              holds the negative byte length of the atomic sequence.
83 ;;              In this case the following applies:
85 ;;              r0:     PC of the first instruction after the atomic
86 ;;                      write-back instruction (exit point).
87 ;;                      The entry point PC of the atomic sequence can be 
88 ;;                      determined by doing r0 + r15.
90 ;;              r1:     Saved r15 stack pointer before entering the
91 ;;                      atomic sequence.
93 ;; An example atomic add sequence would look like:
95 ;;      mova    .Lend,r0                ! .Lend must be 4-byte aligned.
96 ;;      mov     r15,r1
97 ;;      .align 2                        ! Insert aligning nop if needed.
98 ;;      mov     #(.Lstart - .Lend),r15  ! Enter atomic sequence
99 ;;.Lstart:
100 ;;      mov.l   @r4,r2                  ! read value
101 ;;      add     r2,r5                   ! modify value
102 ;;      mov.l   r5,@r4                  ! write-back
103 ;;.Lend:
104 ;;      mov     r1,r15                  ! Exit atomic sequence
105 ;;                                      ! r2 holds the previous value.
106 ;;                                      ! r5 holds the new value.
108 ;; Notice that due to the restrictions of the mova instruction, the .Lend
109 ;; label must always be 4-byte aligned.  Aligning the .Lend label would
110 ;; potentially insert a nop after the write-back instruction which could
111 ;; make the sequence to be rewound, although it has already passed the
112 ;; write-back instruction.  This would make it execute twice.
113 ;; For correct operation the atomic sequences must not be rewound after
114 ;; they have passed the write-back instruction.
116 ;; This is model works only on SH3* and SH4* because the stack pointer (r15)
117 ;; is set to an invalid pointer temporarily.  SH1* and SH2* CPUs will try
118 ;; to push SR and PC registers on the stack when an interrupt / exception
119 ;; occurs, and thus require the stack pointer (r15) always to be valid.
122 ;; TCB Software Atomics (-matomic-model=soft-tcb)
124 ;; This model is a variation of the gUSA model.  The concept of rewindable
125 ;; atomic sequences is the same, but it does not use the stack pointer (r15)
126 ;; for signaling the 'is in atomic sequence' condition.  Instead, a variable
127 ;; in the thread control block (TCB) is set to hold the exit point of the
128 ;; atomic sequence.  This assumes that the GBR is used as a thread pointer
129 ;; register.  The offset of the variable in the TCB to be used must be
130 ;; specified with an additional option 'gbr-offset', such as:
131 ;;      -matomic-model=soft-tcb,gbr-offset=4
133 ;; For this model the following atomic sequence ABI is used.
134 ;; 
135 ;; @(#x,gbr) == 0:  Execution context is not in an atomic sequence.
137 ;; @(#x,gbr) != 0:  Execution context is in an atomic sequence.  In this
138 ;;                  case the following applies:
140 ;;                  @(#x,gbr):  PC of the first instruction after the atomic
141 ;;                              write-back instruction (exit point).
143 ;;                  r1:         Negative byte length of the atomic sequence.
144 ;;                              The entry point PC of the sequence can be
145 ;;                              determined by doing @(#x,gbr) + r1
147 ;; Note: #x is the user specified gbr-offset.
150 ;; Interrupt-Flipping Software Atomics (-matomic-model=soft-imask)
152 ;; This model achieves atomicity by temporarily disabling interrupts for
153 ;; the duration of the atomic sequence.  This works only when the program
154 ;; runs in privileged mode but does not require any support from the
155 ;; interrupt / exception handling code.  There is no particular ABI.
156 ;; To disable interrupts the SR.IMASK bits are set to '1111'.
157 ;; This method is not as efficient as the other software atomic models,
158 ;; since loading and storing SR (in order to flip interrupts on / off)
159 ;; requires using multi-cycle instructions.  Moreover, it can potentially
160 ;; increase the interrupt latency which might be important for hard-realtime
161 ;; applications.
164 ;; Compatibility Notes
166 ;; On single-core SH4A CPUs software atomic aware interrupt / exception code
167 ;; is actually compatible with user code that utilizes hardware atomics.
168 ;; Since SImode hardware atomic sequences are more compact on SH4A they are
169 ;; always used, regardless of the selected atomic model.  This atomic model
170 ;; mixing can be disabled by setting the 'strict' flag, like:
171 ;;      -matomic-model=soft-gusa,strict
173 ;; The software atomic models are generally compatible with each other,
174 ;; but the interrupt / exception handling code has to support both gUSA and
175 ;; TCB models.
177 ;; The current atomic support is limited to QImode, HImode and SImode 
178 ;; atomic operations.  DImode operations could also be implemented but
179 ;; would require some ABI modifications to support multiple-instruction
180 ;; write-back.  This is because SH1/SH2/SH3/SH4 does not have a DImode
181 ;; store instruction.  DImode stores must be split into two SImode stores.
183 (define_c_enum "unspec" [
184   UNSPEC_ATOMIC
187 (define_c_enum "unspecv" [
188   UNSPECV_CMPXCHG_1
189   UNSPECV_CMPXCHG_2
190   UNSPECV_CMPXCHG_3
193 (define_mode_attr i124extend_insn [(QI "exts.b") (HI "exts.w") (SI "mov")])
195 (define_code_iterator FETCHOP [plus minus ior xor and])
196 (define_code_attr fetchop_name
197   [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")])
199 (define_code_attr fetchop_predicate
200   [(plus "atomic_arith_operand") (minus "register_operand")
201    (ior "atomic_logical_operand") (xor "atomic_logical_operand")
202    (and "atomic_logical_operand")])
204 (define_code_attr fetchop_constraint
205   [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
207 ;;------------------------------------------------------------------------------
208 ;; comapre and swap
210 (define_expand "atomic_compare_and_swap<mode>"
211   [(match_operand:SI 0 "register_operand" "")           ;; bool success output
212    (match_operand:QIHISI 1 "register_operand" "")       ;; oldval output
213    (match_operand:QIHISI 2 "memory_operand" "")         ;; memory
214    (match_operand:QIHISI 3 "atomic_arith_operand" "")   ;; expected input
215    (match_operand:QIHISI 4 "atomic_arith_operand" "")   ;; newval input
216    (match_operand:SI 5 "const_int_operand" "")          ;; is_weak
217    (match_operand:SI 6 "const_int_operand" "")          ;; success model
218    (match_operand:SI 7 "const_int_operand" "")]         ;; failure model
219   "TARGET_ATOMIC_ANY"
221   rtx addr = force_reg (Pmode, XEXP (operands[2], 0));
222   rtx old_val = gen_lowpart (SImode, operands[1]);
223   rtx exp_val = operands[3];
224   rtx new_val = operands[4];
225   rtx atomic_insn;
227   if (TARGET_ATOMIC_HARD_LLCS
228       || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
229     atomic_insn = gen_atomic_compare_and_swap<mode>_hard (old_val, addr,
230                                                           exp_val, new_val);
231   else if (TARGET_ATOMIC_SOFT_GUSA)
232     atomic_insn = gen_atomic_compare_and_swap<mode>_soft_gusa (old_val, addr,
233                       exp_val, new_val);
234   else if (TARGET_ATOMIC_SOFT_TCB)
235     atomic_insn = gen_atomic_compare_and_swap<mode>_soft_tcb (old_val, addr,
236                       exp_val, new_val, TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
237   else if (TARGET_ATOMIC_SOFT_IMASK)
238     atomic_insn = gen_atomic_compare_and_swap<mode>_soft_imask (old_val, addr,
239                       exp_val, new_val);
240   else
241     FAIL;
243   emit_insn (atomic_insn);
245   if (<MODE>mode == QImode)
246     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[1]),
247                                      operands[1]));
248   else if (<MODE>mode == HImode)
249     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[1]),
250                                      operands[1]));
251   emit_insn (gen_movsi (operands[0], gen_rtx_REG (SImode, T_REG)));
252   DONE;
255 (define_insn "atomic_compare_and_swapsi_hard"
256   [(set (match_operand:SI 0 "register_operand" "=&r")
257         (unspec_volatile:SI
258           [(mem:SI (match_operand:SI 1 "register_operand" "r"))
259            (match_operand:SI 2 "arith_operand" "rI08")
260            (match_operand:SI 3 "arith_operand" "rI08")]
261           UNSPECV_CMPXCHG_1))
262    (set (mem:SI (match_dup 1))
263         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_2))
264    (set (reg:SI T_REG)
265         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
266    (clobber (reg:SI R0_REG))]
267   "TARGET_ATOMIC_HARD_LLCS
268    || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
270   return "\r0:  movli.l @%1,r0"         "\n"
271          "      cmp/eq  %2,r0"          "\n"
272          "      bf{.|/}s        0f"     "\n"
273          "      mov     r0,%0"          "\n"
274          "      mov     %3,r0"          "\n"
275          "      movco.l r0,@%1"         "\n"
276          "      bf      0b"             "\n"
277          "0:";
279   [(set_attr "length" "14")])
281 (define_insn "atomic_compare_and_swap<mode>_hard"
282   [(set (match_operand:SI 0 "register_operand" "=&r")
283         (unspec_volatile:SI
284           [(mem:QIHI (match_operand:SI 1 "register_operand" "r"))
285            (match_operand:QIHI 2 "register_operand" "r")
286            (match_operand:QIHI 3 "register_operand" "r")]
287           UNSPECV_CMPXCHG_1))
288    (set (mem:QIHI (match_dup 1))
289         (unspec_volatile:QIHI [(const_int 0)] UNSPECV_CMPXCHG_2))
290    (set (reg:SI T_REG)
291         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
292    (clobber (reg:SI R0_REG))
293    (clobber (match_scratch:SI 4 "=&r"))
294    (clobber (match_scratch:SI 5 "=&r"))
295    (clobber (match_scratch:SI 6 "=1"))]
296   "TARGET_ATOMIC_HARD_LLCS"
298   return "\r    mov     #-4,%5"                 "\n"
299          "      <i124extend_insn>       %2,%4"  "\n"
300          "      and     %1,%5"                  "\n"
301          "      xor     %5,%1"                  "\n"
302          "      add     r15,%1"                 "\n"
303          "      add     #-4,%1"                 "\n"
304          "0:    movli.l @%5,r0"                 "\n"
305          "      mov.l   r0,@-r15"               "\n"
306          "      mov.<bw>        @%1,%0"         "\n"
307          "      mov.<bw>        %3,@%1"         "\n"
308          "      cmp/eq  %4,%0"                  "\n"
309          "      bf{.|/}s        0f"             "\n"
310          "      mov.l   @r15+,r0"               "\n"
311          "      movco.l r0,@%5"                 "\n"
312          "      bf      0b"                     "\n"
313          "0:";
315   [(set_attr "length" "30")])
317 (define_insn "atomic_compare_and_swap<mode>_soft_gusa"
318   [(set (match_operand:SI 0 "register_operand" "=&u")
319         (unspec_volatile:SI
320           [(mem:QIHISI (match_operand:SI 1 "register_operand" "u"))
321            (match_operand:QIHISI 2 "register_operand" "u")
322            (match_operand:QIHISI 3 "register_operand" "u")]
323           UNSPECV_CMPXCHG_1))
324    (set (mem:QIHISI (match_dup 1))
325         (unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
326    (set (reg:SI T_REG)
327         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
328    (clobber (match_scratch:SI 4 "=&u"))
329    (clobber (reg:SI R0_REG))
330    (clobber (reg:SI R1_REG))]
331   "TARGET_ATOMIC_SOFT_GUSA"
333   return "\r    mova    1f,r0"                  "\n"
334          "      <i124extend_insn>       %2,%4"  "\n"
335          "      .align 2"                       "\n"
336          "      mov     r15,r1"                 "\n"
337          "      mov     #(0f-1f),r15"           "\n"
338          "0:    mov.<bwl>       @%1,%0"         "\n"
339          "      cmp/eq  %0,%4"                  "\n"
340          "      bf      1f"                     "\n"
341          "      mov.<bwl>       %3,@%1"         "\n"
342          "1:    mov     r1,r15";
344   [(set_attr "length" "20")])
346 (define_insn "atomic_compare_and_swap<mode>_soft_tcb"
347   [(set (match_operand:SI 0 "register_operand" "=&r")
348         (unspec_volatile:SI
349           [(mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
350            (match_operand:QIHISI 2 "register_operand" "r")
351            (match_operand:QIHISI 3 "register_operand" "r")]
352           UNSPECV_CMPXCHG_1))
353    (set (mem:QIHISI (match_dup 1))
354         (unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
355    (set (reg:SI T_REG)
356         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
357    (use (match_operand:SI 4 "gbr_displacement"))
358    (clobber (match_scratch:SI 5 "=&r"))
359    (clobber (reg:SI R0_REG))
360    (clobber (reg:SI R1_REG))]
361   "TARGET_ATOMIC_SOFT_TCB"
363   return "\r    mova    1f,r0"                  "\n"
364          "      .align 2"                       "\n"
365          "      <i124extend_insn>       %2,%5"  "\n"
366          "      mov     #(0f-1f),r1"            "\n"
367          "      mov.l   r0,@(%O4,gbr)"          "\n"
368          "0:    mov.<bwl>       @%1,%0"         "\n"
369          "      mov     #0,r0"                  "\n"
370          "      cmp/eq  %0,%5"                  "\n"
371          "      bf      1f"                     "\n"
372          "      mov.<bwl>       %3,@%1"         "\n"
373          "1:    mov.l   r0,@(%O4,gbr)";
375   [(set_attr "length" "22")])
377 (define_insn "atomic_compare_and_swap<mode>_soft_imask"
378   [(set (match_operand:SI 0 "register_operand" "=&z")
379         (unspec_volatile:SI
380           [(mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
381            (match_operand:QIHISI 2 "register_operand" "r")
382            (match_operand:QIHISI 3 "register_operand" "r")]
383           UNSPECV_CMPXCHG_1))
384    (set (mem:QIHISI (match_dup 1))
385         (unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
386    (set (reg:SI T_REG)
387         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
388    (clobber (match_scratch:SI 4 "=&r"))
389    (clobber (match_scratch:SI 5 "=&r"))]
390   "TARGET_ATOMIC_SOFT_IMASK"
392   /* The comparison result is supposed to be in T_REG.
393      Notice that restoring SR will overwrite the T_REG.  We handle this by
394      rotating the T_REG into the saved SR before restoring SR.  On SH2A we
395      can do one insn shorter by using the bst insn.  */
396   if (!TARGET_SH2A)
397     return "\r  stc     sr,%0"                  "\n"
398            "    <i124extend_insn>       %2,%4"  "\n"
399            "    mov     %0,%5"                  "\n"
400            "    or      #0xF0,%0"               "\n"
401            "    shlr    %5"                     "\n"
402            "    ldc     %0,sr"                  "\n"
403            "    mov.<bwl>       @%1,%0"         "\n"
404            "    cmp/eq  %4,%0"                  "\n"
405            "    bf      1f"                     "\n"
406            "    mov.<bwl>       %3,@%1"         "\n"
407            "1:  rotcl   %5"                     "\n"
408            "    ldc     %5,sr";
409   else
410     return "\r  stc     sr,%0"                  "\n"
411            "    <i124extend_insn>       %2,%4"  "\n"
412            "    mov     %0,%5"                  "\n"
413            "    or      #0xF0,%0"               "\n"
414            "    ldc     %0,sr"                  "\n"
415            "    mov.<bwl>       @%1,%0"         "\n"
416            "    cmp/eq  %4,%0"                  "\n"
417            "    bst     #0,%5"                  "\n"
418            "    bf      1f"                     "\n"
419            "    mov.<bwl>       %3,@%1"         "\n"
420            "1:  ldc     %5,sr";
422   [(set (attr "length") (if_then_else (match_test "!TARGET_SH2A")
423                                       (const_string "24")
424                                       (const_string "22")))])
426 ;;------------------------------------------------------------------------------
427 ;; read - write - return old value
429 (define_expand "atomic_exchange<mode>"
430   [(match_operand:QIHISI 0 "register_operand" "")       ;; oldval output
431    (match_operand:QIHISI 1 "memory_operand" "")         ;; memory
432    (match_operand:QIHISI 2 "atomic_arith_operand" "")   ;; newval input
433    (match_operand:SI 3 "const_int_operand" "")]         ;; memory model
434   "TARGET_ATOMIC_ANY"
436   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
437   rtx val = operands[2];
438   rtx atomic_insn;
440   if (TARGET_ATOMIC_HARD_LLCS
441       || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
442     atomic_insn = gen_atomic_exchange<mode>_hard (operands[0], addr, val);
443   else if (TARGET_ATOMIC_SOFT_GUSA)
444     atomic_insn = gen_atomic_exchange<mode>_soft_gusa (operands[0], addr, val);
445   else if (TARGET_ATOMIC_SOFT_TCB)
446     atomic_insn = gen_atomic_exchange<mode>_soft_tcb (operands[0], addr, val,
447                       TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
448   else if (TARGET_ATOMIC_SOFT_IMASK)
449     atomic_insn = gen_atomic_exchange<mode>_soft_imask (operands[0], addr, val);
450   else
451     FAIL;
453   emit_insn (atomic_insn);
455   if (<MODE>mode == QImode)
456     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
457                                      operands[0]));
458   else if (<MODE>mode == HImode)
459     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
460                                      operands[0]));
461   DONE;
464 (define_insn "atomic_exchangesi_hard"
465   [(set (match_operand:SI 0 "register_operand" "=&r")
466         (mem:SI (match_operand:SI 1 "register_operand" "r")))
467    (set (mem:SI (match_dup 1))
468         (unspec:SI
469           [(match_operand:SI 2 "arith_operand" "rI08")] UNSPEC_ATOMIC))
470    (clobber (reg:SI R0_REG))]
471   "TARGET_ATOMIC_HARD_LLCS
472    || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
474   return "\r0:  movli.l @%1,r0"         "\n"
475          "      mov     r0,%0"          "\n"
476          "      mov     %2,r0"          "\n"
477          "      movco.l r0,@%1"         "\n"
478          "      bf      0b";
480   [(set_attr "length" "10")])
482 (define_insn "atomic_exchange<mode>_hard"
483   [(set (match_operand:QIHI 0 "register_operand" "=&r")
484         (mem:QIHI (match_operand:SI 1 "register_operand" "r")))
485    (set (mem:QIHI (match_dup 1))
486         (unspec:QIHI
487           [(match_operand:QIHI 2 "register_operand" "r")] UNSPEC_ATOMIC))
488    (clobber (reg:SI R0_REG))
489    (clobber (match_scratch:SI 3 "=&r"))
490    (clobber (match_scratch:SI 4 "=1"))]
491   "TARGET_ATOMIC_HARD_LLCS"
493   return "\r    mov     #-4,%3"                 "\n"
494          "      and     %1,%3"                  "\n"
495          "      xor     %3,%1"                  "\n"
496          "      add     r15,%1"                 "\n"
497          "      add     #-4,%1"                 "\n"
498          "0:    movli.l @%3,r0"                 "\n"
499          "      mov.l   r0,@-r15"               "\n"
500          "      mov.<bw>        @%1,%0"         "\n"
501          "      mov.<bw>        %2,@%1"         "\n"
502          "      mov.l   @r15+,r0"               "\n"
503          "      movco.l r0,@%3"                 "\n"
504          "      bf      0b";
506   [(set_attr "length" "24")])
508 (define_insn "atomic_exchange<mode>_soft_gusa"
509   [(set (match_operand:QIHISI 0 "register_operand" "=&u")
510         (mem:QIHISI (match_operand:SI 1 "register_operand" "u")))
511    (set (mem:QIHISI (match_dup 1))
512         (unspec:QIHISI
513           [(match_operand:QIHISI 2 "register_operand" "u")] UNSPEC_ATOMIC))
514    (clobber (reg:SI R0_REG))
515    (clobber (reg:SI R1_REG))]
516   "TARGET_ATOMIC_SOFT_GUSA"
518   return "\r    mova    1f,r0"                  "\n"
519          "      .align 2"                       "\n"
520          "      mov     r15,r1"                 "\n"
521          "      mov     #(0f-1f),r15"           "\n"
522          "0:    mov.<bwl>       @%1,%0"         "\n"
523          "      mov.<bwl>       %2,@%1"         "\n"
524          "1:    mov     r1,r15";
526   [(set_attr "length" "14")])
528 (define_insn "atomic_exchange<mode>_soft_tcb"
529   [(set (match_operand:QIHISI 0 "register_operand" "=&r")
530         (mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
531    (set (mem:QIHISI (match_dup 1))
532         (unspec:QIHISI
533           [(match_operand:QIHISI 2 "register_operand" "r")] UNSPEC_ATOMIC))
534    (clobber (reg:SI R0_REG))
535    (clobber (reg:SI R1_REG))
536    (use (match_operand:SI 3 "gbr_displacement"))]
537   "TARGET_ATOMIC_SOFT_TCB"
539   return "\r    mova    1f,r0"                  "\n"
540          "      mov     #(0f-1f),r1"            "\n"
541          "      .align 2"                       "\n"
542          "      mov.l   r0,@(%O3,gbr)"          "\n"
543          "0:    mov.<bwl>       @%1,%0"         "\n"
544          "      mov     #0,r0"                  "\n"
545          "      mov.<bwl>       %2,@%1"         "\n"
546          "1:    mov.l   r0,@(%O3,gbr)";
548   [(set_attr "length" "16")])
550 (define_insn "atomic_exchange<mode>_soft_imask"
551   [(set (match_operand:QIHISI 0 "register_operand" "=&z")
552         (mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
553    (set (mem:QIHISI (match_dup 1))
554         (unspec:QIHISI
555           [(match_operand:QIHISI 2 "register_operand" "r")] UNSPEC_ATOMIC))
556    (clobber (match_scratch:SI 3 "=&r"))]
557   "TARGET_ATOMIC_SOFT_IMASK"
559   return "\r    stc     sr,%0"                  "\n"
560          "      mov     %0,%3"                  "\n"
561          "      or      #0xF0,%0"               "\n"
562          "      ldc     %0,sr"                  "\n"
563          "      mov.<bwl>       @%1,%0"         "\n"
564          "      mov.<bwl>       %2,@%1"         "\n"
565          "      ldc     %3,sr";
567   [(set_attr "length" "14")])
569 ;;------------------------------------------------------------------------------
570 ;; read - add|sub|or|and|xor|nand - write - return old value
572 (define_expand "atomic_fetch_<fetchop_name><mode>"
573   [(set (match_operand:QIHISI 0 "register_operand" "")
574         (match_operand:QIHISI 1 "memory_operand" ""))
575    (set (match_dup 1)
576         (unspec:QIHISI
577           [(FETCHOP:QIHISI (match_dup 1)
578              (match_operand:QIHISI 2 "<fetchop_predicate>" ""))]
579           UNSPEC_ATOMIC))
580    (match_operand:SI 3 "const_int_operand" "")]
581   "TARGET_ATOMIC_ANY"
583   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
584   rtx atomic_insn;
586   if (TARGET_ATOMIC_HARD_LLCS
587       || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
588     atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_hard (operands[0], addr,
589                                                               operands[2]);
590   else if (TARGET_ATOMIC_SOFT_GUSA)
591     atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_gusa (operands[0],
592                       addr, operands[2]);
593   else if (TARGET_ATOMIC_SOFT_TCB)
594     atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_tcb (operands[0],
595                       addr, operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
596   else if (TARGET_ATOMIC_SOFT_IMASK)
597     atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_imask (operands[0],
598                       addr, operands[2]);
599   else
600     FAIL;
602   emit_insn (atomic_insn);
604   if (<MODE>mode == QImode)
605     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
606                                      operands[0]));
607   else if (<MODE>mode == HImode)
608     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
609                                      operands[0]));
610   DONE;
613 (define_insn "atomic_fetch_<fetchop_name>si_hard"
614   [(set (match_operand:SI 0 "register_operand" "=&r")
615         (mem:SI (match_operand:SI 1 "register_operand" "r")))
616    (set (mem:SI (match_dup 1))
617         (unspec:SI
618           [(FETCHOP:SI (mem:SI (match_dup 1))
619              (match_operand:SI 2 "<fetchop_predicate>" "<fetchop_constraint>"))]
620           UNSPEC_ATOMIC))
621    (clobber (reg:SI R0_REG))]
622   "TARGET_ATOMIC_HARD_LLCS
623    || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
625   return "\r0:  movli.l @%1,r0"         "\n"
626          "      mov     r0,%0"          "\n"
627          "      <fetchop_name>  %2,r0"  "\n"
628          "      movco.l r0,@%1"         "\n"
629          "      bf      0b";
631   [(set_attr "length" "10")])
633 (define_insn "atomic_fetch_<fetchop_name><mode>_hard"
634   [(set (match_operand:QIHI 0 "register_operand" "=&r")
635         (mem:QIHI (match_operand:SI 1 "register_operand" "r")))
636    (set (mem:QIHI (match_dup 1))
637         (unspec:QIHI
638           [(FETCHOP:QIHI (mem:QIHI (match_dup 1))
639              (match_operand:QIHI 2 "<fetchop_predicate>" "<fetchop_constraint>"))]
640           UNSPEC_ATOMIC))
641    (clobber (reg:SI R0_REG))
642    (clobber (match_scratch:SI 3 "=&r"))
643    (clobber (match_scratch:SI 4 "=1"))]
644   "TARGET_ATOMIC_HARD_LLCS"
646   return "\r    mov     #-4,%3"                 "\n"
647          "      and     %1,%3"                  "\n"
648          "      xor     %3,%1"                  "\n"
649          "      add     r15,%1"                 "\n"
650          "      add     #-4,%1"                 "\n"
651          "0:    movli.l @%3,r0"                 "\n"
652          "      mov.l   r0,@-r15"               "\n"
653          "      mov.<bw>        @%1,r0"         "\n"
654          "      mov     r0,%0"                  "\n"
655          "      <fetchop_name>  %2,r0"          "\n"
656          "      mov.<bw>        r0,@%1"         "\n"
657          "      mov.l   @r15+,r0"               "\n"
658          "      movco.l r0,@%3"                 "\n"
659          "      bf      0b";
661   [(set_attr "length" "28")])
663 (define_insn "atomic_fetch_<fetchop_name><mode>_soft_gusa"
664   [(set (match_operand:QIHISI 0 "register_operand" "=&u")
665         (mem:QIHISI (match_operand:SI 1 "register_operand" "u")))
666    (set (mem:QIHISI (match_dup 1))
667         (unspec:QIHISI
668           [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1))
669              (match_operand:QIHISI 2 "register_operand" "u"))]
670           UNSPEC_ATOMIC))
671    (clobber (match_scratch:QIHISI 3 "=&u"))
672    (clobber (reg:SI R0_REG))
673    (clobber (reg:SI R1_REG))]
674   "TARGET_ATOMIC_SOFT_GUSA"
676   return "\r    mova    1f,r0"                  "\n"
677          "      .align 2"                       "\n"
678          "      mov     r15,r1"                 "\n"
679          "      mov     #(0f-1f),r15"           "\n"
680          "0:    mov.<bwl>       @%1,%0"         "\n"
681          "      mov     %0,%3"                  "\n"
682          "      <fetchop_name>  %2,%3"          "\n"
683          "      mov.<bwl>       %3,@%1"         "\n"
684          "1:    mov     r1,r15";
686   [(set_attr "length" "18")])
688 (define_insn "atomic_fetch_<fetchop_name><mode>_soft_tcb"
689   [(set (match_operand:QIHISI 0 "register_operand" "=&r")
690         (mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
691    (set (mem:QIHISI (match_dup 1))
692         (unspec:QIHISI
693           [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1))
694              (match_operand:QIHISI 2 "register_operand" "r"))]
695           UNSPEC_ATOMIC))
696    (use (match_operand:SI 3 "gbr_displacement"))
697    (clobber (match_scratch:QIHISI 4 "=&r"))
698    (clobber (reg:SI R0_REG))
699    (clobber (reg:SI R1_REG))]
700   "TARGET_ATOMIC_SOFT_TCB"
702   return "\r    mova    1f,r0"                  "\n"
703          "      mov     #(0f-1f),r1"            "\n"
704          "      .align 2"                       "\n"
705          "      mov.l   r0,@(%O3,gbr)"          "\n"
706          "0:    mov.<bwl>       @%1,%0"         "\n"
707          "      mov     #0,r0"                  "\n"
708          "      mov     %0,%4"                  "\n"
709          "      <fetchop_name>  %2,%4"          "\n"
710          "      mov.<bwl>       %4,@%1"         "\n"
711          "1:    mov.l   r0,@(%O3,gbr)";
713   [(set_attr "length" "20")])
715 (define_insn "atomic_fetch_<fetchop_name><mode>_soft_imask"
716   [(set (match_operand:QIHISI 0 "register_operand" "=&z")
717         (mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
718    (set (mem:QIHISI (match_dup 1))
719         (unspec:QIHISI
720           [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1))
721              (match_operand:QIHISI 2 "register_operand" "r"))]
722           UNSPEC_ATOMIC))
723    (clobber (match_scratch:QIHISI 3 "=&r"))
724    (clobber (match_scratch:SI 4 "=&r"))]
725   "TARGET_ATOMIC_SOFT_IMASK"
727   return "\r    stc     sr,%0"                  "\n"
728          "      mov     %0,%4"                  "\n"
729          "      or      #0xF0,%0"               "\n"
730          "      ldc     %0,sr"                  "\n"
731          "      mov.<bwl>       @%1,%0"         "\n"
732          "      mov     %0,%3"                  "\n"
733          "      <fetchop_name>  %2,%3"          "\n"
734          "      mov.<bwl>       %3,@%1"         "\n"
735          "      ldc     %4,sr";
737   [(set_attr "length" "18")])
739 (define_expand "atomic_fetch_nand<mode>"
740   [(set (match_operand:QIHISI 0 "register_operand" "")
741         (match_operand:QIHISI 1 "memory_operand" ""))
742    (set (match_dup 1)
743         (unspec:QIHISI
744           [(not:QIHISI (and:QIHISI (match_dup 1)
745                        (match_operand:QIHISI 2 "atomic_logical_operand" "")))]
746           UNSPEC_ATOMIC))
747    (match_operand:SI 3 "const_int_operand" "")]
748   "TARGET_ATOMIC_ANY"
750   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
751   rtx atomic_insn;
753   if (TARGET_ATOMIC_HARD_LLCS
754       || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
755     atomic_insn = gen_atomic_fetch_nand<mode>_hard (operands[0], addr,
756                                                     operands[2]);
757   else if (TARGET_ATOMIC_SOFT_GUSA)
758     atomic_insn = gen_atomic_fetch_nand<mode>_soft_gusa (operands[0], addr,
759                                                          operands[2]);
760   else if (TARGET_ATOMIC_SOFT_TCB)
761     atomic_insn = gen_atomic_fetch_nand<mode>_soft_tcb (operands[0], addr,
762                       operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
763   else if (TARGET_ATOMIC_SOFT_IMASK)
764     atomic_insn = gen_atomic_fetch_nand<mode>_soft_imask (operands[0], addr,
765                                                           operands[2]);
766   else
767     FAIL;
769   emit_insn (atomic_insn);
771   if (<MODE>mode == QImode)
772     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
773                                      operands[0]));
774   else if (<MODE>mode == HImode)
775     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
776                                      operands[0]));
777   DONE;
780 (define_insn "atomic_fetch_nandsi_hard"
781   [(set (match_operand:SI 0 "register_operand" "=&r")
782         (mem:SI (match_operand:SI 1 "register_operand" "r")))
783    (set (mem:SI (match_dup 1))
784         (unspec:SI
785           [(not:SI (and:SI (mem:SI (match_dup 1))
786                    (match_operand:SI 2 "logical_operand" "rK08")))]
787           UNSPEC_ATOMIC))
788    (clobber (reg:SI R0_REG))]
789   "TARGET_ATOMIC_HARD_LLCS
790    || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
792   return "\r0:  movli.l @%1,r0"         "\n"
793          "      mov     r0,%0"          "\n"
794          "      and     %2,r0"          "\n"
795          "      not     r0,r0"          "\n"
796          "      movco.l r0,@%1"         "\n"
797          "      bf      0b";
799   [(set_attr "length" "12")])
801 (define_insn "atomic_fetch_nand<mode>_hard"
802   [(set (match_operand:QIHI 0 "register_operand" "=&r")
803         (mem:QIHI (match_operand:SI 1 "register_operand" "r")))
804    (set (mem:QIHI (match_dup 1))
805         (unspec:QIHI
806           [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1))
807                      (match_operand:QIHI 2 "logical_operand" "rK08")))]
808           UNSPEC_ATOMIC))
809    (clobber (reg:SI R0_REG))
810    (clobber (match_scratch:SI 3 "=&r"))
811    (clobber (match_scratch:SI 4 "=1"))]
812   "TARGET_ATOMIC_HARD_LLCS"
814   return "\r    mov     #-4,%3"                 "\n"
815          "      and     %1,%3"                  "\n"
816          "      xor     %3,%1"                  "\n"
817          "      add     r15,%1"                 "\n"
818          "      add     #-4,%1"                 "\n"
819          "0:    movli.l @%3,r0"                 "\n"
820          "      mov.l   r0,@-r15"               "\n"
821          "      mov.<bw>        @%1,r0"         "\n"
822          "      mov     r0,%0"                  "\n"
823          "      and     %2,r0"                  "\n"
824          "      not     r0,r0"                  "\n"
825          "      mov.<bw>        r0,@%1"         "\n"
826          "      mov.l   @r15+,r0"               "\n"
827          "      movco.l r0,@%3"                 "\n"
828          "      bf      0b";
830   [(set_attr "length" "30")])
832 (define_insn "atomic_fetch_nand<mode>_soft_gusa"
833   [(set (match_operand:QIHISI 0 "register_operand" "=&u")
834         (mem:QIHISI (match_operand:SI 1 "register_operand" "u")))
835    (set (mem:QIHISI (match_dup 1))
836         (unspec:QIHISI
837           [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1))
838              (match_operand:QIHISI 2 "register_operand" "u")))]
839           UNSPEC_ATOMIC))
840    (clobber (match_scratch:QIHISI 3 "=&u"))
841    (clobber (reg:SI R0_REG))
842    (clobber (reg:SI R1_REG))]
843   "TARGET_ATOMIC_SOFT_GUSA"
845   return "\r    mova    1f,r0"                  "\n"
846          "      mov     r15,r1"                 "\n"
847          "      .align 2"                       "\n"
848          "      mov     #(0f-1f),r15"           "\n"
849          "0:    mov.<bwl>       @%1,%0"         "\n"
850          "      mov     %2,%3"                  "\n"
851          "      and     %0,%3"                  "\n"
852          "      not     %3,%3"                  "\n"
853          "      mov.<bwl>       %3,@%1"         "\n"
854          "1:    mov     r1,r15";
856   [(set_attr "length" "20")])
858 (define_insn "atomic_fetch_nand<mode>_soft_tcb"
859   [(set (match_operand:QIHISI 0 "register_operand" "=&r")
860         (mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
861    (set (mem:QIHISI (match_dup 1))
862         (unspec:QIHISI
863           [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1))
864              (match_operand:QIHISI 2 "register_operand" "r")))]
865           UNSPEC_ATOMIC))
866    (use (match_operand:SI 3 "gbr_displacement"))
867    (clobber (match_scratch:QIHISI 4 "=&r"))
868    (clobber (reg:SI R0_REG))
869    (clobber (reg:SI R1_REG))]
870   "TARGET_ATOMIC_SOFT_TCB"
872   return "\r    mova    1f,r0"                  "\n"
873          "      .align 2"                       "\n"
874          "      mov     #(0f-1f),r1"            "\n"
875          "      mov.l   r0,@(%O3,gbr)"          "\n"
876          "0:    mov.<bwl>       @%1,%0"         "\n"
877          "      mov     #0,r0"                  "\n"
878          "      mov     %2,%4"                  "\n"
879          "      and     %0,%4"                  "\n"
880          "      not     %4,%4"                  "\n"
881          "      mov.<bwl>       %4,@%1"         "\n"
882          "1:    mov.l   r0,@(%O3,gbr)";
884   [(set_attr "length" "22")])
886 (define_insn "atomic_fetch_nand<mode>_soft_imask"
887   [(set (match_operand:QIHISI 0 "register_operand" "=&z")
888         (mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
889    (set (mem:QIHISI (match_dup 1))
890         (unspec:QIHISI
891           [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1))
892              (match_operand:QIHISI 2 "register_operand" "r")))]
893           UNSPEC_ATOMIC))
894    (clobber (match_scratch:QIHISI 3 "=&r"))
895    (clobber (match_scratch:SI 4 "=&r"))]
896   "TARGET_ATOMIC_SOFT_IMASK"
898   return "\r    stc     sr,%0"                  "\n"
899          "      mov     %0,%4"                  "\n"
900          "      or      #0xF0,%0"               "\n"
901          "      ldc     %0,sr"                  "\n"
902          "      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          "      stc     %4,sr";
909   [(set_attr "length" "20")])
911 ;;------------------------------------------------------------------------------
912 ;; read - add|sub|or|and|xor|nand - write - return new value
914 (define_expand "atomic_<fetchop_name>_fetch<mode>"
915   [(set (match_operand:QIHISI 0 "register_operand" "")
916         (FETCHOP:QIHISI
917           (match_operand:QIHISI 1 "memory_operand" "")
918           (match_operand:QIHISI 2 "<fetchop_predicate>" "")))
919    (set (match_dup 1)
920         (unspec:QIHISI
921           [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))]
922           UNSPEC_ATOMIC))
923    (match_operand:SI 3 "const_int_operand" "")]
924   "TARGET_ATOMIC_ANY"
926   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
927   rtx atomic_insn;
929   if (TARGET_ATOMIC_HARD_LLCS
930       || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
931     atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_hard (operands[0], addr,
932                                                               operands[2]);
933   else if (TARGET_ATOMIC_SOFT_GUSA)
934     atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_gusa (operands[0],
935                       addr, operands[2]);
936   else if (TARGET_ATOMIC_SOFT_TCB)
937     atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_tcb (operands[0],
938                       addr, operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
939   else if (TARGET_ATOMIC_SOFT_IMASK)
940     atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_imask (operands[0],
941                       addr, operands[2]);
942   else
943     FAIL;
945   emit_insn (atomic_insn);
947   if (<MODE>mode == QImode)
948     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
949                                      operands[0]));
950   else if (<MODE>mode == HImode)
951     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
952                                      operands[0]));
953   DONE;
956 (define_insn "atomic_<fetchop_name>_fetchsi_hard"
957   [(set (match_operand:SI 0 "register_operand" "=&z")
958         (FETCHOP:SI
959           (mem:SI (match_operand:SI 1 "register_operand" "r"))
960           (match_operand:SI 2 "<fetchop_predicate>" "<fetchop_constraint>")))
961    (set (mem:SI (match_dup 1))
962         (unspec:SI
963           [(FETCHOP:SI (mem:SI (match_dup 1)) (match_dup 2))]
964           UNSPEC_ATOMIC))]
965   "TARGET_ATOMIC_HARD_LLCS
966    || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
968   return "\r0:  movli.l @%1,%0"         "\n"
969          "      <fetchop_name>  %2,%0"  "\n"
970          "      movco.l %0,@%1"         "\n"
971          "      bf      0b";
973   [(set_attr "length" "8")])
975 (define_insn "atomic_<fetchop_name>_fetch<mode>_hard"
976   [(set (match_operand:QIHI 0 "register_operand" "=&r")
977         (FETCHOP:QIHI
978           (mem:QIHI (match_operand:SI 1 "register_operand" "r"))
979           (match_operand:QIHI 2 "<fetchop_predicate>" "<fetchop_constraint>")))
980    (set (mem:QIHI (match_dup 1))
981         (unspec:QIHI
982           [(FETCHOP:QIHI (mem:QIHI (match_dup 1)) (match_dup 2))]
983           UNSPEC_ATOMIC))
984    (clobber (reg:SI R0_REG))
985    (clobber (match_scratch:SI 3 "=&r"))
986    (clobber (match_scratch:SI 4 "=1"))]
987   "TARGET_ATOMIC_HARD_LLCS"
989   return "\r    mov     #-4,%3"                 "\n"
990          "      and     %1,%3"                  "\n"
991          "      xor     %3,%1"                  "\n"
992          "      add     r15,%1"                 "\n"
993          "      add     #-4,%1"                 "\n"
994          "0:    movli.l @%3,r0"                 "\n"
995          "      mov.l   r0,@-r15"               "\n"
996          "      mov.<bw>        @%1,r0"         "\n"
997          "      <fetchop_name>  %2,r0"          "\n"
998          "      mov.<bw>        r0,@%1"         "\n"
999          "      mov     r0,%0"                  "\n"
1000          "      mov.l   @r15+,r0"               "\n"
1001          "      movco.l r0,@%3"                 "\n"
1002          "      bf      0b";
1004   [(set_attr "length" "28")])
1006 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_gusa"
1007   [(set (match_operand:QIHISI 0 "register_operand" "=&u")
1008         (FETCHOP:QIHISI
1009           (mem:QIHISI (match_operand:SI 1 "register_operand" "u"))
1010           (match_operand:QIHISI 2 "register_operand" "u")))
1011    (set (mem:QIHISI (match_dup 1))
1012         (unspec:QIHISI
1013           [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
1014           UNSPEC_ATOMIC))
1015    (clobber (reg:SI R0_REG))
1016    (clobber (reg:SI R1_REG))]
1017   "TARGET_ATOMIC_SOFT_GUSA"
1019   return "\r    mova    1f,r0"                  "\n"
1020          "      mov     r15,r1"                 "\n"
1021          "      .align 2"                       "\n"
1022          "      mov     #(0f-1f),r15"           "\n"
1023          "0:    mov.<bwl>       @%1,%0"         "\n"
1024          "      <fetchop_name>  %2,%0"          "\n"
1025          "      mov.<bwl>       %0,@%1"         "\n"
1026          "1:    mov     r1,r15";
1028   [(set_attr "length" "16")])
1030 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_tcb"
1031   [(set (match_operand:QIHISI 0 "register_operand" "=&r")
1032         (FETCHOP:QIHISI
1033           (mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
1034           (match_operand:QIHISI 2 "register_operand" "r")))
1035    (set (mem:QIHISI (match_dup 1))
1036         (unspec:QIHISI
1037           [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
1038           UNSPEC_ATOMIC))
1039    (clobber (reg:SI R0_REG))
1040    (clobber (reg:SI R1_REG))
1041    (use (match_operand:SI 3 "gbr_displacement"))]
1042   "TARGET_ATOMIC_SOFT_TCB"
1044   return "\r    mova    1f,r0"                  "\n"
1045          "      .align 2"                       "\n"
1046          "      mov     #(0f-1f),r1"            "\n"
1047          "      mov.l   r0,@(%O3,gbr)"          "\n"
1048          "0:    mov.<bwl>       @%1,%0"         "\n"
1049          "      mov     #0,r0"                  "\n"
1050          "      <fetchop_name>  %2,%0"          "\n"
1051          "      mov.<bwl>       %0,@%1"         "\n"
1052          "1:    mov.l   r0,@(%O3,gbr)";
1054   [(set_attr "length" "18")])
1056 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_imask"
1057   [(set (match_operand:QIHISI 0 "register_operand" "=&z")
1058         (FETCHOP:QIHISI
1059           (mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
1060           (match_operand:QIHISI 2 "register_operand" "r")))
1061    (set (mem:QIHISI (match_dup 1))
1062         (unspec:QIHISI
1063           [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
1064           UNSPEC_ATOMIC))
1065    (clobber (match_scratch:SI 3 "=&r"))]
1066   "TARGET_ATOMIC_SOFT_IMASK"
1068   return "\r    stc     sr,%0"                  "\n"
1069          "      mov     %0,%3"                  "\n"
1070          "      or      #0xF0,%0"               "\n"
1071          "      ldc     %0,sr"                  "\n"
1072          "      mov.<bwl>       @%1,%0"         "\n"
1073          "      <fetchop_name>  %2,%0"          "\n"
1074          "      mov.<bwl>       %0,@%1"         "\n"
1075          "      ldc     %3,sr";
1077   [(set_attr "length" "16")])
1079 (define_expand "atomic_nand_fetch<mode>"
1080   [(set (match_operand:QIHISI 0 "register_operand" "")
1081         (not:QIHISI (and:QIHISI
1082           (match_operand:QIHISI 1 "memory_operand" "")
1083           (match_operand:QIHISI 2 "atomic_logical_operand" ""))))
1084    (set (match_dup 1)
1085         (unspec:QIHISI
1086           [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))]
1087           UNSPEC_ATOMIC))
1088    (match_operand:SI 3 "const_int_operand" "")]
1089   "TARGET_ATOMIC_ANY"
1091   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
1092   rtx atomic_insn;
1094   if (TARGET_ATOMIC_HARD_LLCS
1095       || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
1096     atomic_insn = gen_atomic_nand_fetch<mode>_hard (operands[0], addr,
1097                                                     operands[2]);
1098   else if (TARGET_ATOMIC_SOFT_GUSA)
1099     atomic_insn = gen_atomic_nand_fetch<mode>_soft_gusa (operands[0], addr,
1100                                                          operands[2]);
1101   else if (TARGET_ATOMIC_SOFT_TCB)
1102     atomic_insn = gen_atomic_nand_fetch<mode>_soft_tcb (operands[0], addr,
1103                       operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
1104   else if (TARGET_ATOMIC_SOFT_IMASK)
1105     atomic_insn = gen_atomic_nand_fetch<mode>_soft_imask (operands[0], addr,
1106                                                           operands[2]);
1107   else
1108     FAIL;
1110   emit_insn (atomic_insn);
1112   if (<MODE>mode == QImode)
1113     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
1114                                      operands[0]));
1115   else if (<MODE>mode == HImode)
1116     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
1117                                      operands[0]));
1118   DONE;
1121 (define_insn "atomic_nand_fetchsi_hard"
1122   [(set (match_operand:SI 0 "register_operand" "=&z")
1123         (not:SI (and:SI (mem:SI (match_operand:SI 1 "register_operand" "r"))
1124                         (match_operand:SI 2 "logical_operand" "rK08"))))
1125    (set (mem:SI (match_dup 1))
1126         (unspec:SI
1127           [(not:SI (and:SI (mem:SI (match_dup 1)) (match_dup 2)))]
1128           UNSPEC_ATOMIC))]
1129   "TARGET_ATOMIC_HARD_LLCS
1130    || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1132   return "\r0:  movli.l @%1,%0"         "\n"
1133          "      and     %2,%0"          "\n"
1134          "      not     %0,%0"          "\n"
1135          "      movco.l %0,@%1"         "\n"
1136          "      bf      0b";
1138   [(set_attr "length" "10")])
1140 (define_insn "atomic_nand_fetch<mode>_hard"
1141   [(set (match_operand:QIHI 0 "register_operand" "=&r")
1142         (not:QIHI
1143           (and:QIHI (mem:QIHI (match_operand:SI 1 "register_operand" "r"))
1144                     (match_operand:QIHI 2 "logical_operand" "rK08"))))
1145    (set (mem:QIHI (match_dup 1))
1146         (unspec:QIHI
1147           [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1)) (match_dup 2)))]
1148           UNSPEC_ATOMIC))
1149    (clobber (reg:SI R0_REG))
1150    (clobber (match_scratch:SI 3 "=&r"))
1151    (clobber (match_scratch:SI 4 "=1"))]
1152   "TARGET_ATOMIC_HARD_LLCS"
1154   return "\r    mov     #-4,%3"                 "\n"
1155          "      and     %1,%3"                  "\n"
1156          "      xor     %3,%1"                  "\n"
1157          "      add     r15,%1"                 "\n"
1158          "      add     #-4,%1"                 "\n"
1159          "0:    movli.l @%3,r0"                 "\n"
1160          "      mov.l   r0,@-r15"               "\n"
1161          "      mov.<bw>        @%1,r0"         "\n"
1162          "      and     %2,r0"                  "\n"
1163          "      not     r0,%0"                  "\n"
1164          "      mov.<bw>        %0,@%1"         "\n"
1165          "      mov.l   @r15+,r0"               "\n"
1166          "      movco.l r0,@%3"                 "\n"
1167          "      bf      0b";
1169   [(set_attr "length" "28")])
1171 (define_insn "atomic_nand_fetch<mode>_soft_gusa"
1172   [(set (match_operand:QIHISI 0 "register_operand" "=&u")
1173         (not:QIHISI (and:QIHISI
1174           (mem:QIHISI (match_operand:SI 1 "register_operand" "u"))
1175           (match_operand:QIHISI 2 "register_operand" "u"))))
1176    (set (mem:QIHISI (match_dup 1))
1177         (unspec:QIHISI
1178           [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
1179           UNSPEC_ATOMIC))
1180    (clobber (reg:SI R0_REG))
1181    (clobber (reg:SI R1_REG))]
1182   "TARGET_ATOMIC_SOFT_GUSA"
1184   return "\r    mova    1f,r0"                  "\n"
1185          "      .align 2"                       "\n"
1186          "      mov     r15,r1"                 "\n"
1187          "      mov     #(0f-1f),r15"           "\n"
1188          "0:    mov.<bwl>       @%1,%0"         "\n"
1189          "      and     %2,%0"                  "\n"
1190          "      not     %0,%0"                  "\n"
1191          "      mov.<bwl>       %0,@%1"         "\n"
1192          "1:    mov     r1,r15";
1194   [(set_attr "length" "18")])
1196 (define_insn "atomic_nand_fetch<mode>_soft_tcb"
1197   [(set (match_operand:QIHISI 0 "register_operand" "=&r")
1198         (not:QIHISI (and:QIHISI
1199           (mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
1200           (match_operand:QIHISI 2 "register_operand" "r"))))
1201    (set (mem:QIHISI (match_dup 1))
1202         (unspec:QIHISI
1203           [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
1204           UNSPEC_ATOMIC))
1205    (clobber (reg:SI R0_REG))
1206    (clobber (reg:SI R1_REG))
1207    (use (match_operand:SI 3 "gbr_displacement"))]
1208   "TARGET_ATOMIC_SOFT_TCB"
1210   return "\r    mova    1f,r0"                  "\n"
1211          "      mov     #(0f-1f),r1"            "\n"
1212          "      .align 2"                       "\n"
1213          "      mov.l   r0,@(%O3,gbr)"          "\n"
1214          "0:    mov.<bwl>       @%1,%0"         "\n"
1215          "      mov     #0,r0"                  "\n"
1216          "      and     %2,%0"                  "\n"
1217          "      not     %0,%0"                  "\n"
1218          "      mov.<bwl>       %0,@%1"         "\n"
1219          "1:    mov.l   r0,@(%O3,gbr)";
1221   [(set_attr "length" "20")])
1223 (define_insn "atomic_nand_fetch<mode>_soft_imask"
1224   [(set (match_operand:QIHISI 0 "register_operand" "=&z")
1225         (not:QIHISI (and:QIHISI
1226           (mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
1227           (match_operand:QIHISI 2 "register_operand" "r"))))
1228    (set (mem:QIHISI (match_dup 1))
1229         (unspec:QIHISI
1230           [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
1231           UNSPEC_ATOMIC))
1232    (clobber (match_scratch:SI 3 "=&r"))]
1233   "TARGET_ATOMIC_SOFT_IMASK"
1235   return "\r    stc     sr,%0"                  "\n"
1236          "      mov     %0,%3"                  "\n"
1237          "      or      #0xF0,%0"               "\n"
1238          "      ldc     %0,sr"                  "\n"
1239          "      mov.<bwl>       @%1,%0"         "\n"
1240          "      and     %2,%0"                  "\n"
1241          "      not     %0,%0"                  "\n"
1242          "      mov.<bwl>       %0,@%1"         "\n"
1243          "      ldc     %3,sr";
1245   [(set_attr "length" "18")])
1247 ;;------------------------------------------------------------------------------
1248 ;; read - test against zero - or with 0x80 - write - return test result
1250 (define_expand "atomic_test_and_set"
1251   [(match_operand:SI 0 "register_operand" "")           ;; bool result output
1252    (match_operand:QI 1 "memory_operand" "")             ;; memory
1253    (match_operand:SI 2 "const_int_operand" "")]         ;; model
1254   "(TARGET_ATOMIC_ANY || TARGET_ENABLE_TAS) && !TARGET_SHMEDIA"
1256   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
1258   if (TARGET_ENABLE_TAS)
1259     emit_insn (gen_tasb (addr));
1260   else
1261     {
1262       rtx val = gen_int_mode (targetm.atomic_test_and_set_trueval, QImode);
1263       val = force_reg (QImode, val);
1265       if (TARGET_ATOMIC_HARD_LLCS)
1266           emit_insn (gen_atomic_test_and_set_hard (addr, val));
1267       else if (TARGET_ATOMIC_SOFT_GUSA)
1268           emit_insn (gen_atomic_test_and_set_soft_gusa (addr, val));
1269       else if (TARGET_ATOMIC_SOFT_TCB)
1270           emit_insn (gen_atomic_test_and_set_soft_tcb (addr, val,
1271                          TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX));
1272       else if (TARGET_ATOMIC_SOFT_IMASK)
1273           emit_insn (gen_atomic_test_and_set_soft_imask (addr, val));
1274       else
1275         FAIL;
1276     }
1278   /* The result of the test op is the inverse of what we are
1279      supposed to return.  Thus invert the T bit.  The inversion will be
1280      potentially optimized away and integrated into surrounding code.  */
1281   emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ()));
1282   DONE;
1285 (define_insn "tasb"
1286   [(set (reg:SI T_REG)
1287         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1288                (const_int 0)))
1289    (set (mem:QI (match_dup 0))
1290         (unspec:QI [(const_int 128)] UNSPEC_ATOMIC))]
1291   "TARGET_ENABLE_TAS && !TARGET_SHMEDIA"
1292   "tas.b        @%0"
1293   [(set_attr "insn_class" "co_group")])
1295 (define_insn "atomic_test_and_set_soft_gusa"
1296   [(set (reg:SI T_REG)
1297         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "u"))
1298                (const_int 0)))
1299    (set (mem:QI (match_dup 0))
1300         (unspec:QI [(match_operand:QI 1 "register_operand" "u")] UNSPEC_ATOMIC))
1301    (clobber (match_scratch:QI 2 "=&u"))
1302    (clobber (reg:SI R0_REG))
1303    (clobber (reg:SI R1_REG))]
1304   "TARGET_ATOMIC_SOFT_GUSA && !TARGET_ENABLE_TAS"
1306   return "\r    mova    1f,r0"          "\n"
1307          "      .align 2"               "\n"
1308          "      mov     r15,r1"         "\n"
1309          "      mov     #(0f-1f),r15"   "\n"
1310          "0:    mov.b   @%0,%2"         "\n"
1311          "      mov.b   %1,@%0"         "\n"
1312          "1:    mov     r1,r15"         "\n"
1313          "      tst     %2,%2";
1315   [(set_attr "length" "16")])
1317 (define_insn "atomic_test_and_set_soft_tcb"
1318   [(set (reg:SI T_REG)
1319         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1320                (const_int 0)))
1321    (set (mem:QI (match_dup 0))
1322         (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
1323    (use (match_operand:SI 2 "gbr_displacement"))
1324    (clobber (match_scratch:QI 3 "=&r"))
1325    (clobber (reg:SI R0_REG))
1326    (clobber (reg:SI R1_REG))]
1327   "TARGET_ATOMIC_SOFT_TCB && !TARGET_ENABLE_TAS"
1329   return "\r    mova    1f,r0"          "\n"
1330          "      mov     #(0f-1f),r1"    "\n"
1331          "      .align 2"               "\n"
1332          "      mov.l   r0,@(%O2,gbr)"  "\n"
1333          "0:    mov.b   @%0,%3"         "\n"
1334          "      mov     #0,r0"          "\n"
1335          "      mov.b   %1,@%0"         "\n"
1336          "1:    mov.l   r0,@(%O2,gbr)"  "\n"
1337          "      tst     %3,%3";
1339   [(set_attr "length" "18")])
1341 (define_insn "atomic_test_and_set_soft_imask"
1342   [(set (reg:SI T_REG)
1343         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1344                (const_int 0)))
1345    (set (mem:QI (match_dup 0))
1346         (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
1347    (clobber (match_scratch:SI 2 "=&r"))
1348    (clobber (reg:SI R0_REG))]
1349   "TARGET_ATOMIC_SOFT_IMASK && !TARGET_ENABLE_TAS"
1351   return "\r    stc     sr,r0"          "\n"
1352          "      mov     r0,%2"          "\n"
1353          "      or      #0xF0,r0"       "\n"
1354          "      ldc     r0,sr"          "\n"
1355          "      mov.b   @%0,r0"         "\n"
1356          "      mov.b   %1,@%0"         "\n"
1357          "      stc     %2,sr"          "\n"
1358          "      tst     r0,r0";
1360   [(set_attr "length" "16")])
1362 (define_insn "atomic_test_and_set_hard"
1363   [(set (reg:SI T_REG)
1364         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1365                (const_int 0)))
1366    (set (mem:QI (match_dup 0))
1367         (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
1368    (clobber (reg:SI R0_REG))
1369    (clobber (match_scratch:SI 2 "=&r"))
1370    (clobber (match_scratch:SI 3 "=&r"))
1371    (clobber (match_scratch:SI 4 "=0"))]
1372   "TARGET_ATOMIC_HARD_LLCS && !TARGET_ENABLE_TAS"
1374   return "\r    mov     #-4,%2"         "\n"
1375          "      and     %0,%2"          "\n"
1376          "      xor     %2,%0"          "\n"
1377          "      add     r15,%0"         "\n"
1378          "      add     #-4,%0"         "\n"
1379          "0:    movli.l @%2,r0"         "\n"
1380          "      mov.l   r0,@-r15"       "\n"
1381          "      mov.b   @%0,%3"         "\n"
1382          "      mov.b   %1,@%0"         "\n"
1383          "      mov.l   @r15+,r0"       "\n"
1384          "      movco.l r0,@%2"         "\n"
1385          "      bf      0b"             "\n"
1386          "      tst     %3,%3";
1388   [(set_attr "length" "26")])