Rebase.
[official-gcc.git] / gcc / config / sh / sync.md
bloba0a22a1f5b7cd3710a29a92fb9deca787048366e
1 ;; GCC machine description for SH synchronization instructions.
2 ;; Copyright (C) 2011-2014 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.
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.
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/>.
21 ;; Atomic integer operations for the Renesas / SuperH SH CPUs.
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.
31 ;; tas.b atomic_test_and_set (-mtas)
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.
42 ;; Hardware Atomics (-matomic-model=hard-llcs; SH4A only)
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.
53 ;; gUSA Software Atomics (-matomic-model=soft-gusa; SH3*, SH4* only)
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.
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...
68 ;;      if (interrupted_context_in_atomic_sequence
69 ;;          && interrupted_pc < atomic_exitpoint)
70 ;;        interrupted_pc = atomic_entrypoint;
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.
76 ;; For this the following atomic sequence ABI is used.
78 ;; r15 >= 0:    Execution context is not in an atomic sequence.
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:
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.
89 ;;              r1:     Saved r15 stack pointer before entering the
90 ;;                      atomic sequence.
92 ;; An example atomic add sequence would look like:
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.
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.
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.
121 ;; TCB Software Atomics (-matomic-model=soft-tcb)
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
132 ;; For this model the following atomic sequence ABI is used.
133 ;; 
134 ;; @(#x,gbr) == 0:  Execution context is not in an atomic sequence.
136 ;; @(#x,gbr) != 0:  Execution context is in an atomic sequence.  In this
137 ;;                  case the following applies:
139 ;;                  @(#x,gbr):  PC of the first instruction after the atomic
140 ;;                              write-back instruction (exit point).
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
146 ;; Note: #x is the user specified gbr-offset.
149 ;; Interrupt-Flipping Software Atomics (-matomic-model=soft-imask)
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.
163 ;; Compatibility Notes
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
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.
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.
182 (define_c_enum "unspec" [
183   UNSPEC_ATOMIC
186 (define_c_enum "unspecv" [
187   UNSPECV_CMPXCHG_1
188   UNSPECV_CMPXCHG_2
189   UNSPECV_CMPXCHG_3
192 (define_mode_attr i124extend_insn [(QI "exts.b") (HI "exts.w") (SI "mov")])
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")])
198 (define_code_attr fetchop_predicate
199   [(plus "atomic_arith_operand") (minus "register_operand")
200    (ior "atomic_logical_operand") (xor "atomic_logical_operand")
201    (and "atomic_logical_operand")])
203 (define_code_attr fetchop_constraint
204   [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
206 ;;------------------------------------------------------------------------------
207 ;; comapre and swap
209 (define_expand "atomic_compare_and_swap<mode>"
210   [(match_operand:SI 0 "register_operand" "")           ;; bool success output
211    (match_operand:QIHISI 1 "register_operand" "")       ;; oldval output
212    (match_operand:QIHISI 2 "memory_operand" "")         ;; memory
213    (match_operand:QIHISI 3 "atomic_arith_operand" "")   ;; expected input
214    (match_operand:QIHISI 4 "atomic_arith_operand" "")   ;; newval input
215    (match_operand:SI 5 "const_int_operand" "")          ;; is_weak
216    (match_operand:SI 6 "const_int_operand" "")          ;; success model
217    (match_operand:SI 7 "const_int_operand" "")]         ;; failure model
218   "TARGET_ATOMIC_ANY"
220   rtx addr = force_reg (Pmode, XEXP (operands[2], 0));
221   rtx old_val = gen_lowpart (SImode, operands[1]);
222   rtx exp_val = operands[3];
223   rtx new_val = operands[4];
224   rtx atomic_insn;
226   if (TARGET_ATOMIC_HARD_LLCS
227       || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
228     atomic_insn = gen_atomic_compare_and_swap<mode>_hard (old_val, addr,
229                                                           exp_val, new_val);
230   else if (TARGET_ATOMIC_SOFT_GUSA)
231     atomic_insn = gen_atomic_compare_and_swap<mode>_soft_gusa (old_val, addr,
232                       exp_val, new_val);
233   else if (TARGET_ATOMIC_SOFT_TCB)
234     atomic_insn = gen_atomic_compare_and_swap<mode>_soft_tcb (old_val, addr,
235                       exp_val, new_val, TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
236   else if (TARGET_ATOMIC_SOFT_IMASK)
237     atomic_insn = gen_atomic_compare_and_swap<mode>_soft_imask (old_val, addr,
238                       exp_val, new_val);
239   else
240     FAIL;
242   emit_insn (atomic_insn);
244   if (<MODE>mode == QImode)
245     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[1]),
246                                      operands[1]));
247   else if (<MODE>mode == HImode)
248     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[1]),
249                                      operands[1]));
250   emit_insn (gen_movsi (operands[0], gen_rtx_REG (SImode, T_REG)));
251   DONE;
254 (define_insn "atomic_compare_and_swapsi_hard"
255   [(set (match_operand:SI 0 "register_operand" "=&r")
256         (unspec_volatile:SI
257           [(mem:SI (match_operand:SI 1 "register_operand" "r"))
258            (match_operand:SI 2 "arith_operand" "rI08")
259            (match_operand:SI 3 "arith_operand" "rI08")]
260           UNSPECV_CMPXCHG_1))
261    (set (mem:SI (match_dup 1))
262         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_2))
263    (set (reg:SI T_REG)
264         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
265    (clobber (reg:SI R0_REG))]
266   "TARGET_ATOMIC_HARD_LLCS
267    || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
269   return "\r0:  movli.l @%1,r0"         "\n"
270          "      cmp/eq  %2,r0"          "\n"
271          "      bf{.|/}s        0f"     "\n"
272          "      mov     r0,%0"          "\n"
273          "      mov     %3,r0"          "\n"
274          "      movco.l r0,@%1"         "\n"
275          "      bf      0b"             "\n"
276          "0:";
278   [(set_attr "length" "14")])
280 (define_insn "atomic_compare_and_swap<mode>_hard"
281   [(set (match_operand:SI 0 "register_operand" "=&r")
282         (unspec_volatile:SI
283           [(mem:QIHI (match_operand:SI 1 "register_operand" "r"))
284            (match_operand:QIHI 2 "register_operand" "r")
285            (match_operand:QIHI 3 "register_operand" "r")]
286           UNSPECV_CMPXCHG_1))
287    (set (mem:QIHI (match_dup 1))
288         (unspec_volatile:QIHI [(const_int 0)] UNSPECV_CMPXCHG_2))
289    (set (reg:SI T_REG)
290         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
291    (clobber (reg:SI R0_REG))
292    (clobber (match_scratch:SI 4 "=&r"))
293    (clobber (match_scratch:SI 5 "=&r"))
294    (clobber (match_scratch:SI 6 "=1"))]
295   "TARGET_ATOMIC_HARD_LLCS"
297   return "\r    mov     #-4,%5"                 "\n"
298          "      <i124extend_insn>       %2,%4"  "\n"
299          "      and     %1,%5"                  "\n"
300          "      xor     %5,%1"                  "\n"
301          "      add     r15,%1"                 "\n"
302          "      add     #-4,%1"                 "\n"
303          "0:    movli.l @%5,r0"                 "\n"
304          "      mov.l   r0,@-r15"               "\n"
305          "      mov.<bw>        @%1,%0"         "\n"
306          "      mov.<bw>        %3,@%1"         "\n"
307          "      cmp/eq  %4,%0"                  "\n"
308          "      bf{.|/}s        0f"             "\n"
309          "      mov.l   @r15+,r0"               "\n"
310          "      movco.l r0,@%5"                 "\n"
311          "      bf      0b"                     "\n"
312          "0:";
314   [(set_attr "length" "30")])
316 (define_insn "atomic_compare_and_swap<mode>_soft_gusa"
317   [(set (match_operand:SI 0 "register_operand" "=&u")
318         (unspec_volatile:SI
319           [(mem:QIHISI (match_operand:SI 1 "register_operand" "u"))
320            (match_operand:QIHISI 2 "register_operand" "u")
321            (match_operand:QIHISI 3 "register_operand" "u")]
322           UNSPECV_CMPXCHG_1))
323    (set (mem:QIHISI (match_dup 1))
324         (unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
325    (set (reg:SI T_REG)
326         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
327    (clobber (match_scratch:SI 4 "=&u"))
328    (clobber (reg:SI R0_REG))
329    (clobber (reg:SI R1_REG))]
330   "TARGET_ATOMIC_SOFT_GUSA"
332   return "\r    mova    1f,r0"                  "\n"
333          "      <i124extend_insn>       %2,%4"  "\n"
334          "      .align 2"                       "\n"
335          "      mov     r15,r1"                 "\n"
336          "      mov     #(0f-1f),r15"           "\n"
337          "0:    mov.<bwl>       @%1,%0"         "\n"
338          "      cmp/eq  %0,%4"                  "\n"
339          "      bf      1f"                     "\n"
340          "      mov.<bwl>       %3,@%1"         "\n"
341          "1:    mov     r1,r15";
343   [(set_attr "length" "20")])
345 (define_insn "atomic_compare_and_swap<mode>_soft_tcb"
346   [(set (match_operand:SI 0 "register_operand" "=&r")
347         (unspec_volatile:SI
348           [(mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
349            (match_operand:QIHISI 2 "register_operand" "r")
350            (match_operand:QIHISI 3 "register_operand" "r")]
351           UNSPECV_CMPXCHG_1))
352    (set (mem:QIHISI (match_dup 1))
353         (unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
354    (set (reg:SI T_REG)
355         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
356    (use (match_operand:SI 4 "gbr_displacement"))
357    (clobber (match_scratch:SI 5 "=&r"))
358    (clobber (reg:SI R0_REG))
359    (clobber (reg:SI R1_REG))]
360   "TARGET_ATOMIC_SOFT_TCB"
362   return "\r    mova    1f,r0"                  "\n"
363          "      .align 2"                       "\n"
364          "      <i124extend_insn>       %2,%5"  "\n"
365          "      mov     #(0f-1f),r1"            "\n"
366          "      mov.l   r0,@(%O4,gbr)"          "\n"
367          "0:    mov.<bwl>       @%1,%0"         "\n"
368          "      mov     #0,r0"                  "\n"
369          "      cmp/eq  %0,%5"                  "\n"
370          "      bf      1f"                     "\n"
371          "      mov.<bwl>       %3,@%1"         "\n"
372          "1:    mov.l   r0,@(%O4,gbr)";
374   [(set_attr "length" "22")])
376 (define_insn "atomic_compare_and_swap<mode>_soft_imask"
377   [(set (match_operand:SI 0 "register_operand" "=&z")
378         (unspec_volatile:SI
379           [(mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
380            (match_operand:QIHISI 2 "register_operand" "r")
381            (match_operand:QIHISI 3 "register_operand" "r")]
382           UNSPECV_CMPXCHG_1))
383    (set (mem:QIHISI (match_dup 1))
384         (unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
385    (set (reg:SI T_REG)
386         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
387    (clobber (match_scratch:SI 4 "=&r"))
388    (clobber (match_scratch:SI 5 "=&r"))]
389   "TARGET_ATOMIC_SOFT_IMASK"
391   /* The comparison result is supposed to be in T_REG.
392      Notice that restoring SR will overwrite the T_REG.  We handle this by
393      rotating the T_REG into the saved SR before restoring SR.  On SH2A we
394      can do one insn shorter by using the bst insn.  */
395   if (!TARGET_SH2A)
396     return "\r  stc     sr,%0"                  "\n"
397            "    <i124extend_insn>       %2,%4"  "\n"
398            "    mov     %0,%5"                  "\n"
399            "    or      #0xF0,%0"               "\n"
400            "    shlr    %5"                     "\n"
401            "    ldc     %0,sr"                  "\n"
402            "    mov.<bwl>       @%1,%0"         "\n"
403            "    cmp/eq  %4,%0"                  "\n"
404            "    bf      1f"                     "\n"
405            "    mov.<bwl>       %3,@%1"         "\n"
406            "1:  rotcl   %5"                     "\n"
407            "    ldc     %5,sr";
408   else
409     return "\r  stc     sr,%0"                  "\n"
410            "    <i124extend_insn>       %2,%4"  "\n"
411            "    mov     %0,%5"                  "\n"
412            "    or      #0xF0,%0"               "\n"
413            "    ldc     %0,sr"                  "\n"
414            "    mov.<bwl>       @%1,%0"         "\n"
415            "    cmp/eq  %4,%0"                  "\n"
416            "    bst     #0,%5"                  "\n"
417            "    bf      1f"                     "\n"
418            "    mov.<bwl>       %3,@%1"         "\n"
419            "1:  ldc     %5,sr";
421   [(set (attr "length") (if_then_else (match_test "!TARGET_SH2A")
422                                       (const_string "24")
423                                       (const_string "22")))])
425 ;;------------------------------------------------------------------------------
426 ;; read - write - return old value
428 (define_expand "atomic_exchange<mode>"
429   [(match_operand:QIHISI 0 "register_operand" "")       ;; oldval output
430    (match_operand:QIHISI 1 "memory_operand" "")         ;; memory
431    (match_operand:QIHISI 2 "atomic_arith_operand" "")   ;; newval input
432    (match_operand:SI 3 "const_int_operand" "")]         ;; memory model
433   "TARGET_ATOMIC_ANY"
435   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
436   rtx val = operands[2];
437   rtx atomic_insn;
439   if (TARGET_ATOMIC_HARD_LLCS
440       || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
441     atomic_insn = gen_atomic_exchange<mode>_hard (operands[0], addr, val);
442   else if (TARGET_ATOMIC_SOFT_GUSA)
443     atomic_insn = gen_atomic_exchange<mode>_soft_gusa (operands[0], addr, val);
444   else if (TARGET_ATOMIC_SOFT_TCB)
445     atomic_insn = gen_atomic_exchange<mode>_soft_tcb (operands[0], addr, val,
446                       TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
447   else if (TARGET_ATOMIC_SOFT_IMASK)
448     atomic_insn = gen_atomic_exchange<mode>_soft_imask (operands[0], addr, val);
449   else
450     FAIL;
452   emit_insn (atomic_insn);
454   if (<MODE>mode == QImode)
455     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
456                                      operands[0]));
457   else if (<MODE>mode == HImode)
458     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
459                                      operands[0]));
460   DONE;
463 (define_insn "atomic_exchangesi_hard"
464   [(set (match_operand:SI 0 "register_operand" "=&r")
465         (mem:SI (match_operand:SI 1 "register_operand" "r")))
466    (set (mem:SI (match_dup 1))
467         (unspec:SI
468           [(match_operand:SI 2 "arith_operand" "rI08")] UNSPEC_ATOMIC))
469    (clobber (reg:SI R0_REG))]
470   "TARGET_ATOMIC_HARD_LLCS
471    || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
473   return "\r0:  movli.l @%1,r0"         "\n"
474          "      mov     r0,%0"          "\n"
475          "      mov     %2,r0"          "\n"
476          "      movco.l r0,@%1"         "\n"
477          "      bf      0b";
479   [(set_attr "length" "10")])
481 (define_insn "atomic_exchange<mode>_hard"
482   [(set (match_operand:QIHI 0 "register_operand" "=&r")
483         (mem:QIHI (match_operand:SI 1 "register_operand" "r")))
484    (set (mem:QIHI (match_dup 1))
485         (unspec:QIHI
486           [(match_operand:QIHI 2 "register_operand" "r")] UNSPEC_ATOMIC))
487    (clobber (reg:SI R0_REG))
488    (clobber (match_scratch:SI 3 "=&r"))
489    (clobber (match_scratch:SI 4 "=1"))]
490   "TARGET_ATOMIC_HARD_LLCS"
492   return "\r    mov     #-4,%3"                 "\n"
493          "      and     %1,%3"                  "\n"
494          "      xor     %3,%1"                  "\n"
495          "      add     r15,%1"                 "\n"
496          "      add     #-4,%1"                 "\n"
497          "0:    movli.l @%3,r0"                 "\n"
498          "      mov.l   r0,@-r15"               "\n"
499          "      mov.<bw>        @%1,%0"         "\n"
500          "      mov.<bw>        %2,@%1"         "\n"
501          "      mov.l   @r15+,r0"               "\n"
502          "      movco.l r0,@%3"                 "\n"
503          "      bf      0b";
505   [(set_attr "length" "24")])
507 (define_insn "atomic_exchange<mode>_soft_gusa"
508   [(set (match_operand:QIHISI 0 "register_operand" "=&u")
509         (mem:QIHISI (match_operand:SI 1 "register_operand" "u")))
510    (set (mem:QIHISI (match_dup 1))
511         (unspec:QIHISI
512           [(match_operand:QIHISI 2 "register_operand" "u")] UNSPEC_ATOMIC))
513    (clobber (reg:SI R0_REG))
514    (clobber (reg:SI R1_REG))]
515   "TARGET_ATOMIC_SOFT_GUSA"
517   return "\r    mova    1f,r0"                  "\n"
518          "      .align 2"                       "\n"
519          "      mov     r15,r1"                 "\n"
520          "      mov     #(0f-1f),r15"           "\n"
521          "0:    mov.<bwl>       @%1,%0"         "\n"
522          "      mov.<bwl>       %2,@%1"         "\n"
523          "1:    mov     r1,r15";
525   [(set_attr "length" "14")])
527 (define_insn "atomic_exchange<mode>_soft_tcb"
528   [(set (match_operand:QIHISI 0 "register_operand" "=&r")
529         (mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
530    (set (mem:QIHISI (match_dup 1))
531         (unspec:QIHISI
532           [(match_operand:QIHISI 2 "register_operand" "r")] UNSPEC_ATOMIC))
533    (clobber (reg:SI R0_REG))
534    (clobber (reg:SI R1_REG))
535    (use (match_operand:SI 3 "gbr_displacement"))]
536   "TARGET_ATOMIC_SOFT_TCB"
538   return "\r    mova    1f,r0"                  "\n"
539          "      mov     #(0f-1f),r1"            "\n"
540          "      .align 2"                       "\n"
541          "      mov.l   r0,@(%O3,gbr)"          "\n"
542          "0:    mov.<bwl>       @%1,%0"         "\n"
543          "      mov     #0,r0"                  "\n"
544          "      mov.<bwl>       %2,@%1"         "\n"
545          "1:    mov.l   r0,@(%O3,gbr)";
547   [(set_attr "length" "16")])
549 (define_insn "atomic_exchange<mode>_soft_imask"
550   [(set (match_operand:QIHISI 0 "register_operand" "=&z")
551         (mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
552    (set (mem:QIHISI (match_dup 1))
553         (unspec:QIHISI
554           [(match_operand:QIHISI 2 "register_operand" "r")] UNSPEC_ATOMIC))
555    (clobber (match_scratch:SI 3 "=&r"))]
556   "TARGET_ATOMIC_SOFT_IMASK"
558   return "\r    stc     sr,%0"                  "\n"
559          "      mov     %0,%3"                  "\n"
560          "      or      #0xF0,%0"               "\n"
561          "      ldc     %0,sr"                  "\n"
562          "      mov.<bwl>       @%1,%0"         "\n"
563          "      mov.<bwl>       %2,@%1"         "\n"
564          "      ldc     %3,sr";
566   [(set_attr "length" "14")])
568 ;;------------------------------------------------------------------------------
569 ;; read - add|sub|or|and|xor|nand - write - return old value
571 (define_expand "atomic_fetch_<fetchop_name><mode>"
572   [(set (match_operand:QIHISI 0 "register_operand" "")
573         (match_operand:QIHISI 1 "memory_operand" ""))
574    (set (match_dup 1)
575         (unspec:QIHISI
576           [(FETCHOP:QIHISI (match_dup 1)
577              (match_operand:QIHISI 2 "<fetchop_predicate>" ""))]
578           UNSPEC_ATOMIC))
579    (match_operand:SI 3 "const_int_operand" "")]
580   "TARGET_ATOMIC_ANY"
582   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
583   rtx atomic_insn;
585   if (TARGET_ATOMIC_HARD_LLCS
586       || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
587     atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_hard (operands[0], addr,
588                                                               operands[2]);
589   else if (TARGET_ATOMIC_SOFT_GUSA)
590     atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_gusa (operands[0],
591                       addr, operands[2]);
592   else if (TARGET_ATOMIC_SOFT_TCB)
593     atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_tcb (operands[0],
594                       addr, operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
595   else if (TARGET_ATOMIC_SOFT_IMASK)
596     atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_imask (operands[0],
597                       addr, operands[2]);
598   else
599     FAIL;
601   emit_insn (atomic_insn);
603   if (<MODE>mode == QImode)
604     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
605                                      operands[0]));
606   else if (<MODE>mode == HImode)
607     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
608                                      operands[0]));
609   DONE;
612 (define_insn "atomic_fetch_<fetchop_name>si_hard"
613   [(set (match_operand:SI 0 "register_operand" "=&r")
614         (mem:SI (match_operand:SI 1 "register_operand" "r")))
615    (set (mem:SI (match_dup 1))
616         (unspec:SI
617           [(FETCHOP:SI (mem:SI (match_dup 1))
618              (match_operand:SI 2 "<fetchop_predicate>" "<fetchop_constraint>"))]
619           UNSPEC_ATOMIC))
620    (clobber (reg:SI R0_REG))]
621   "TARGET_ATOMIC_HARD_LLCS
622    || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
624   return "\r0:  movli.l @%1,r0"         "\n"
625          "      mov     r0,%0"          "\n"
626          "      <fetchop_name>  %2,r0"  "\n"
627          "      movco.l r0,@%1"         "\n"
628          "      bf      0b";
630   [(set_attr "length" "10")])
632 (define_insn "atomic_fetch_<fetchop_name><mode>_hard"
633   [(set (match_operand:QIHI 0 "register_operand" "=&r")
634         (mem:QIHI (match_operand:SI 1 "register_operand" "r")))
635    (set (mem:QIHI (match_dup 1))
636         (unspec:QIHI
637           [(FETCHOP:QIHI (mem:QIHI (match_dup 1))
638              (match_operand:QIHI 2 "<fetchop_predicate>" "<fetchop_constraint>"))]
639           UNSPEC_ATOMIC))
640    (clobber (reg:SI R0_REG))
641    (clobber (match_scratch:SI 3 "=&r"))
642    (clobber (match_scratch:SI 4 "=1"))]
643   "TARGET_ATOMIC_HARD_LLCS"
645   return "\r    mov     #-4,%3"                 "\n"
646          "      and     %1,%3"                  "\n"
647          "      xor     %3,%1"                  "\n"
648          "      add     r15,%1"                 "\n"
649          "      add     #-4,%1"                 "\n"
650          "0:    movli.l @%3,r0"                 "\n"
651          "      mov.l   r0,@-r15"               "\n"
652          "      mov.<bw>        @%1,r0"         "\n"
653          "      mov     r0,%0"                  "\n"
654          "      <fetchop_name>  %2,r0"          "\n"
655          "      mov.<bw>        r0,@%1"         "\n"
656          "      mov.l   @r15+,r0"               "\n"
657          "      movco.l r0,@%3"                 "\n"
658          "      bf      0b";
660   [(set_attr "length" "28")])
662 (define_insn "atomic_fetch_<fetchop_name><mode>_soft_gusa"
663   [(set (match_operand:QIHISI 0 "register_operand" "=&u")
664         (mem:QIHISI (match_operand:SI 1 "register_operand" "u")))
665    (set (mem:QIHISI (match_dup 1))
666         (unspec:QIHISI
667           [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1))
668              (match_operand:QIHISI 2 "register_operand" "u"))]
669           UNSPEC_ATOMIC))
670    (clobber (match_scratch:QIHISI 3 "=&u"))
671    (clobber (reg:SI R0_REG))
672    (clobber (reg:SI R1_REG))]
673   "TARGET_ATOMIC_SOFT_GUSA"
675   return "\r    mova    1f,r0"                  "\n"
676          "      .align 2"                       "\n"
677          "      mov     r15,r1"                 "\n"
678          "      mov     #(0f-1f),r15"           "\n"
679          "0:    mov.<bwl>       @%1,%0"         "\n"
680          "      mov     %0,%3"                  "\n"
681          "      <fetchop_name>  %2,%3"          "\n"
682          "      mov.<bwl>       %3,@%1"         "\n"
683          "1:    mov     r1,r15";
685   [(set_attr "length" "18")])
687 (define_insn "atomic_fetch_<fetchop_name><mode>_soft_tcb"
688   [(set (match_operand:QIHISI 0 "register_operand" "=&r")
689         (mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
690    (set (mem:QIHISI (match_dup 1))
691         (unspec:QIHISI
692           [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1))
693              (match_operand:QIHISI 2 "register_operand" "r"))]
694           UNSPEC_ATOMIC))
695    (use (match_operand:SI 3 "gbr_displacement"))
696    (clobber (match_scratch:QIHISI 4 "=&r"))
697    (clobber (reg:SI R0_REG))
698    (clobber (reg:SI R1_REG))]
699   "TARGET_ATOMIC_SOFT_TCB"
701   return "\r    mova    1f,r0"                  "\n"
702          "      mov     #(0f-1f),r1"            "\n"
703          "      .align 2"                       "\n"
704          "      mov.l   r0,@(%O3,gbr)"          "\n"
705          "0:    mov.<bwl>       @%1,%0"         "\n"
706          "      mov     #0,r0"                  "\n"
707          "      mov     %0,%4"                  "\n"
708          "      <fetchop_name>  %2,%4"          "\n"
709          "      mov.<bwl>       %4,@%1"         "\n"
710          "1:    mov.l   r0,@(%O3,gbr)";
712   [(set_attr "length" "20")])
714 (define_insn "atomic_fetch_<fetchop_name><mode>_soft_imask"
715   [(set (match_operand:QIHISI 0 "register_operand" "=&z")
716         (mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
717    (set (mem:QIHISI (match_dup 1))
718         (unspec:QIHISI
719           [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1))
720              (match_operand:QIHISI 2 "register_operand" "r"))]
721           UNSPEC_ATOMIC))
722    (clobber (match_scratch:QIHISI 3 "=&r"))
723    (clobber (match_scratch:SI 4 "=&r"))]
724   "TARGET_ATOMIC_SOFT_IMASK"
726   return "\r    stc     sr,%0"                  "\n"
727          "      mov     %0,%4"                  "\n"
728          "      or      #0xF0,%0"               "\n"
729          "      ldc     %0,sr"                  "\n"
730          "      mov.<bwl>       @%1,%0"         "\n"
731          "      mov     %0,%3"                  "\n"
732          "      <fetchop_name>  %2,%3"          "\n"
733          "      mov.<bwl>       %3,@%1"         "\n"
734          "      ldc     %4,sr";
736   [(set_attr "length" "18")])
738 (define_expand "atomic_fetch_nand<mode>"
739   [(set (match_operand:QIHISI 0 "register_operand" "")
740         (match_operand:QIHISI 1 "memory_operand" ""))
741    (set (match_dup 1)
742         (unspec:QIHISI
743           [(not:QIHISI (and:QIHISI (match_dup 1)
744                        (match_operand:QIHISI 2 "atomic_logical_operand" "")))]
745           UNSPEC_ATOMIC))
746    (match_operand:SI 3 "const_int_operand" "")]
747   "TARGET_ATOMIC_ANY"
749   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
750   rtx atomic_insn;
752   if (TARGET_ATOMIC_HARD_LLCS
753       || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
754     atomic_insn = gen_atomic_fetch_nand<mode>_hard (operands[0], addr,
755                                                     operands[2]);
756   else if (TARGET_ATOMIC_SOFT_GUSA)
757     atomic_insn = gen_atomic_fetch_nand<mode>_soft_gusa (operands[0], addr,
758                                                          operands[2]);
759   else if (TARGET_ATOMIC_SOFT_TCB)
760     atomic_insn = gen_atomic_fetch_nand<mode>_soft_tcb (operands[0], addr,
761                       operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
762   else if (TARGET_ATOMIC_SOFT_IMASK)
763     atomic_insn = gen_atomic_fetch_nand<mode>_soft_imask (operands[0], addr,
764                                                           operands[2]);
765   else
766     FAIL;
768   emit_insn (atomic_insn);
770   if (<MODE>mode == QImode)
771     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
772                                      operands[0]));
773   else if (<MODE>mode == HImode)
774     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
775                                      operands[0]));
776   DONE;
779 (define_insn "atomic_fetch_nandsi_hard"
780   [(set (match_operand:SI 0 "register_operand" "=&r")
781         (mem:SI (match_operand:SI 1 "register_operand" "r")))
782    (set (mem:SI (match_dup 1))
783         (unspec:SI
784           [(not:SI (and:SI (mem:SI (match_dup 1))
785                    (match_operand:SI 2 "logical_operand" "rK08")))]
786           UNSPEC_ATOMIC))
787    (clobber (reg:SI R0_REG))]
788   "TARGET_ATOMIC_HARD_LLCS
789    || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
791   return "\r0:  movli.l @%1,r0"         "\n"
792          "      mov     r0,%0"          "\n"
793          "      and     %2,r0"          "\n"
794          "      not     r0,r0"          "\n"
795          "      movco.l r0,@%1"         "\n"
796          "      bf      0b";
798   [(set_attr "length" "12")])
800 (define_insn "atomic_fetch_nand<mode>_hard"
801   [(set (match_operand:QIHI 0 "register_operand" "=&r")
802         (mem:QIHI (match_operand:SI 1 "register_operand" "r")))
803    (set (mem:QIHI (match_dup 1))
804         (unspec:QIHI
805           [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1))
806                      (match_operand:QIHI 2 "logical_operand" "rK08")))]
807           UNSPEC_ATOMIC))
808    (clobber (reg:SI R0_REG))
809    (clobber (match_scratch:SI 3 "=&r"))
810    (clobber (match_scratch:SI 4 "=1"))]
811   "TARGET_ATOMIC_HARD_LLCS"
813   return "\r    mov     #-4,%3"                 "\n"
814          "      and     %1,%3"                  "\n"
815          "      xor     %3,%1"                  "\n"
816          "      add     r15,%1"                 "\n"
817          "      add     #-4,%1"                 "\n"
818          "0:    movli.l @%3,r0"                 "\n"
819          "      mov.l   r0,@-r15"               "\n"
820          "      mov.<bw>        @%1,r0"         "\n"
821          "      mov     r0,%0"                  "\n"
822          "      and     %2,r0"                  "\n"
823          "      not     r0,r0"                  "\n"
824          "      mov.<bw>        r0,@%1"         "\n"
825          "      mov.l   @r15+,r0"               "\n"
826          "      movco.l r0,@%3"                 "\n"
827          "      bf      0b";
829   [(set_attr "length" "30")])
831 (define_insn "atomic_fetch_nand<mode>_soft_gusa"
832   [(set (match_operand:QIHISI 0 "register_operand" "=&u")
833         (mem:QIHISI (match_operand:SI 1 "register_operand" "u")))
834    (set (mem:QIHISI (match_dup 1))
835         (unspec:QIHISI
836           [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1))
837              (match_operand:QIHISI 2 "register_operand" "u")))]
838           UNSPEC_ATOMIC))
839    (clobber (match_scratch:QIHISI 3 "=&u"))
840    (clobber (reg:SI R0_REG))
841    (clobber (reg:SI R1_REG))]
842   "TARGET_ATOMIC_SOFT_GUSA"
844   return "\r    mova    1f,r0"                  "\n"
845          "      mov     r15,r1"                 "\n"
846          "      .align 2"                       "\n"
847          "      mov     #(0f-1f),r15"           "\n"
848          "0:    mov.<bwl>       @%1,%0"         "\n"
849          "      mov     %2,%3"                  "\n"
850          "      and     %0,%3"                  "\n"
851          "      not     %3,%3"                  "\n"
852          "      mov.<bwl>       %3,@%1"         "\n"
853          "1:    mov     r1,r15";
855   [(set_attr "length" "20")])
857 (define_insn "atomic_fetch_nand<mode>_soft_tcb"
858   [(set (match_operand:QIHISI 0 "register_operand" "=&r")
859         (mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
860    (set (mem:QIHISI (match_dup 1))
861         (unspec:QIHISI
862           [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1))
863              (match_operand:QIHISI 2 "register_operand" "r")))]
864           UNSPEC_ATOMIC))
865    (use (match_operand:SI 3 "gbr_displacement"))
866    (clobber (match_scratch:QIHISI 4 "=&r"))
867    (clobber (reg:SI R0_REG))
868    (clobber (reg:SI R1_REG))]
869   "TARGET_ATOMIC_SOFT_TCB"
871   return "\r    mova    1f,r0"                  "\n"
872          "      .align 2"                       "\n"
873          "      mov     #(0f-1f),r1"            "\n"
874          "      mov.l   r0,@(%O3,gbr)"          "\n"
875          "0:    mov.<bwl>       @%1,%0"         "\n"
876          "      mov     #0,r0"                  "\n"
877          "      mov     %2,%4"                  "\n"
878          "      and     %0,%4"                  "\n"
879          "      not     %4,%4"                  "\n"
880          "      mov.<bwl>       %4,@%1"         "\n"
881          "1:    mov.l   r0,@(%O3,gbr)";
883   [(set_attr "length" "22")])
885 (define_insn "atomic_fetch_nand<mode>_soft_imask"
886   [(set (match_operand:QIHISI 0 "register_operand" "=&z")
887         (mem:QIHISI (match_operand:SI 1 "register_operand" "r")))
888    (set (mem:QIHISI (match_dup 1))
889         (unspec:QIHISI
890           [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1))
891              (match_operand:QIHISI 2 "register_operand" "r")))]
892           UNSPEC_ATOMIC))
893    (clobber (match_scratch:QIHISI 3 "=&r"))
894    (clobber (match_scratch:SI 4 "=&r"))]
895   "TARGET_ATOMIC_SOFT_IMASK"
897   return "\r    stc     sr,%0"                  "\n"
898          "      mov     %0,%4"                  "\n"
899          "      or      #0xF0,%0"               "\n"
900          "      ldc     %0,sr"                  "\n"
901          "      mov.<bwl>       @%1,%0"         "\n"
902          "      mov     %2,%3"                  "\n"
903          "      and     %0,%3"                  "\n"
904          "      not     %3,%3"                  "\n"
905          "      mov.<bwl>       %3,@%1"         "\n"
906          "      stc     %4,sr";
908   [(set_attr "length" "20")])
910 ;;------------------------------------------------------------------------------
911 ;; read - add|sub|or|and|xor|nand - write - return new value
913 (define_expand "atomic_<fetchop_name>_fetch<mode>"
914   [(set (match_operand:QIHISI 0 "register_operand" "")
915         (FETCHOP:QIHISI
916           (match_operand:QIHISI 1 "memory_operand" "")
917           (match_operand:QIHISI 2 "<fetchop_predicate>" "")))
918    (set (match_dup 1)
919         (unspec:QIHISI
920           [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))]
921           UNSPEC_ATOMIC))
922    (match_operand:SI 3 "const_int_operand" "")]
923   "TARGET_ATOMIC_ANY"
925   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
926   rtx atomic_insn;
928   if (TARGET_ATOMIC_HARD_LLCS
929       || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
930     atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_hard (operands[0], addr,
931                                                               operands[2]);
932   else if (TARGET_ATOMIC_SOFT_GUSA)
933     atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_gusa (operands[0],
934                       addr, operands[2]);
935   else if (TARGET_ATOMIC_SOFT_TCB)
936     atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_tcb (operands[0],
937                       addr, operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
938   else if (TARGET_ATOMIC_SOFT_IMASK)
939     atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_imask (operands[0],
940                       addr, operands[2]);
941   else
942     FAIL;
944   emit_insn (atomic_insn);
946   if (<MODE>mode == QImode)
947     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
948                                      operands[0]));
949   else if (<MODE>mode == HImode)
950     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
951                                      operands[0]));
952   DONE;
955 (define_insn "atomic_<fetchop_name>_fetchsi_hard"
956   [(set (match_operand:SI 0 "register_operand" "=&z")
957         (FETCHOP:SI
958           (mem:SI (match_operand:SI 1 "register_operand" "r"))
959           (match_operand:SI 2 "<fetchop_predicate>" "<fetchop_constraint>")))
960    (set (mem:SI (match_dup 1))
961         (unspec:SI
962           [(FETCHOP:SI (mem:SI (match_dup 1)) (match_dup 2))]
963           UNSPEC_ATOMIC))]
964   "TARGET_ATOMIC_HARD_LLCS
965    || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
967   return "\r0:  movli.l @%1,%0"         "\n"
968          "      <fetchop_name>  %2,%0"  "\n"
969          "      movco.l %0,@%1"         "\n"
970          "      bf      0b";
972   [(set_attr "length" "8")])
974 (define_insn "atomic_<fetchop_name>_fetch<mode>_hard"
975   [(set (match_operand:QIHI 0 "register_operand" "=&r")
976         (FETCHOP:QIHI
977           (mem:QIHI (match_operand:SI 1 "register_operand" "r"))
978           (match_operand:QIHI 2 "<fetchop_predicate>" "<fetchop_constraint>")))
979    (set (mem:QIHI (match_dup 1))
980         (unspec:QIHI
981           [(FETCHOP:QIHI (mem:QIHI (match_dup 1)) (match_dup 2))]
982           UNSPEC_ATOMIC))
983    (clobber (reg:SI R0_REG))
984    (clobber (match_scratch:SI 3 "=&r"))
985    (clobber (match_scratch:SI 4 "=1"))]
986   "TARGET_ATOMIC_HARD_LLCS"
988   return "\r    mov     #-4,%3"                 "\n"
989          "      and     %1,%3"                  "\n"
990          "      xor     %3,%1"                  "\n"
991          "      add     r15,%1"                 "\n"
992          "      add     #-4,%1"                 "\n"
993          "0:    movli.l @%3,r0"                 "\n"
994          "      mov.l   r0,@-r15"               "\n"
995          "      mov.<bw>        @%1,r0"         "\n"
996          "      <fetchop_name>  %2,r0"          "\n"
997          "      mov.<bw>        r0,@%1"         "\n"
998          "      mov     r0,%0"                  "\n"
999          "      mov.l   @r15+,r0"               "\n"
1000          "      movco.l r0,@%3"                 "\n"
1001          "      bf      0b";
1003   [(set_attr "length" "28")])
1005 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_gusa"
1006   [(set (match_operand:QIHISI 0 "register_operand" "=&u")
1007         (FETCHOP:QIHISI
1008           (mem:QIHISI (match_operand:SI 1 "register_operand" "u"))
1009           (match_operand:QIHISI 2 "register_operand" "u")))
1010    (set (mem:QIHISI (match_dup 1))
1011         (unspec:QIHISI
1012           [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
1013           UNSPEC_ATOMIC))
1014    (clobber (reg:SI R0_REG))
1015    (clobber (reg:SI R1_REG))]
1016   "TARGET_ATOMIC_SOFT_GUSA"
1018   return "\r    mova    1f,r0"                  "\n"
1019          "      mov     r15,r1"                 "\n"
1020          "      .align 2"                       "\n"
1021          "      mov     #(0f-1f),r15"           "\n"
1022          "0:    mov.<bwl>       @%1,%0"         "\n"
1023          "      <fetchop_name>  %2,%0"          "\n"
1024          "      mov.<bwl>       %0,@%1"         "\n"
1025          "1:    mov     r1,r15";
1027   [(set_attr "length" "16")])
1029 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_tcb"
1030   [(set (match_operand:QIHISI 0 "register_operand" "=&r")
1031         (FETCHOP:QIHISI
1032           (mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
1033           (match_operand:QIHISI 2 "register_operand" "r")))
1034    (set (mem:QIHISI (match_dup 1))
1035         (unspec:QIHISI
1036           [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
1037           UNSPEC_ATOMIC))
1038    (clobber (reg:SI R0_REG))
1039    (clobber (reg:SI R1_REG))
1040    (use (match_operand:SI 3 "gbr_displacement"))]
1041   "TARGET_ATOMIC_SOFT_TCB"
1043   return "\r    mova    1f,r0"                  "\n"
1044          "      .align 2"                       "\n"
1045          "      mov     #(0f-1f),r1"            "\n"
1046          "      mov.l   r0,@(%O3,gbr)"          "\n"
1047          "0:    mov.<bwl>       @%1,%0"         "\n"
1048          "      mov     #0,r0"                  "\n"
1049          "      <fetchop_name>  %2,%0"          "\n"
1050          "      mov.<bwl>       %0,@%1"         "\n"
1051          "1:    mov.l   r0,@(%O3,gbr)";
1053   [(set_attr "length" "18")])
1055 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_imask"
1056   [(set (match_operand:QIHISI 0 "register_operand" "=&z")
1057         (FETCHOP:QIHISI
1058           (mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
1059           (match_operand:QIHISI 2 "register_operand" "r")))
1060    (set (mem:QIHISI (match_dup 1))
1061         (unspec:QIHISI
1062           [(FETCHOP:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2))]
1063           UNSPEC_ATOMIC))
1064    (clobber (match_scratch:SI 3 "=&r"))]
1065   "TARGET_ATOMIC_SOFT_IMASK"
1067   return "\r    stc     sr,%0"                  "\n"
1068          "      mov     %0,%3"                  "\n"
1069          "      or      #0xF0,%0"               "\n"
1070          "      ldc     %0,sr"                  "\n"
1071          "      mov.<bwl>       @%1,%0"         "\n"
1072          "      <fetchop_name>  %2,%0"          "\n"
1073          "      mov.<bwl>       %0,@%1"         "\n"
1074          "      ldc     %3,sr";
1076   [(set_attr "length" "16")])
1078 (define_expand "atomic_nand_fetch<mode>"
1079   [(set (match_operand:QIHISI 0 "register_operand" "")
1080         (not:QIHISI (and:QIHISI
1081           (match_operand:QIHISI 1 "memory_operand" "")
1082           (match_operand:QIHISI 2 "atomic_logical_operand" ""))))
1083    (set (match_dup 1)
1084         (unspec:QIHISI
1085           [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))]
1086           UNSPEC_ATOMIC))
1087    (match_operand:SI 3 "const_int_operand" "")]
1088   "TARGET_ATOMIC_ANY"
1090   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
1091   rtx atomic_insn;
1093   if (TARGET_ATOMIC_HARD_LLCS
1094       || (TARGET_SH4A_ARCH && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
1095     atomic_insn = gen_atomic_nand_fetch<mode>_hard (operands[0], addr,
1096                                                     operands[2]);
1097   else if (TARGET_ATOMIC_SOFT_GUSA)
1098     atomic_insn = gen_atomic_nand_fetch<mode>_soft_gusa (operands[0], addr,
1099                                                          operands[2]);
1100   else if (TARGET_ATOMIC_SOFT_TCB)
1101     atomic_insn = gen_atomic_nand_fetch<mode>_soft_tcb (operands[0], addr,
1102                       operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
1103   else if (TARGET_ATOMIC_SOFT_IMASK)
1104     atomic_insn = gen_atomic_nand_fetch<mode>_soft_imask (operands[0], addr,
1105                                                           operands[2]);
1106   else
1107     FAIL;
1109   emit_insn (atomic_insn);
1111   if (<MODE>mode == QImode)
1112     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
1113                                      operands[0]));
1114   else if (<MODE>mode == HImode)
1115     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
1116                                      operands[0]));
1117   DONE;
1120 (define_insn "atomic_nand_fetchsi_hard"
1121   [(set (match_operand:SI 0 "register_operand" "=&z")
1122         (not:SI (and:SI (mem:SI (match_operand:SI 1 "register_operand" "r"))
1123                         (match_operand:SI 2 "logical_operand" "rK08"))))
1124    (set (mem:SI (match_dup 1))
1125         (unspec:SI
1126           [(not:SI (and:SI (mem:SI (match_dup 1)) (match_dup 2)))]
1127           UNSPEC_ATOMIC))]
1128   "TARGET_ATOMIC_HARD_LLCS
1129    || (TARGET_SH4A_ARCH && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1131   return "\r0:  movli.l @%1,%0"         "\n"
1132          "      and     %2,%0"          "\n"
1133          "      not     %0,%0"          "\n"
1134          "      movco.l %0,@%1"         "\n"
1135          "      bf      0b";
1137   [(set_attr "length" "10")])
1139 (define_insn "atomic_nand_fetch<mode>_hard"
1140   [(set (match_operand:QIHI 0 "register_operand" "=&r")
1141         (not:QIHI
1142           (and:QIHI (mem:QIHI (match_operand:SI 1 "register_operand" "r"))
1143                     (match_operand:QIHI 2 "logical_operand" "rK08"))))
1144    (set (mem:QIHI (match_dup 1))
1145         (unspec:QIHI
1146           [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1)) (match_dup 2)))]
1147           UNSPEC_ATOMIC))
1148    (clobber (reg:SI R0_REG))
1149    (clobber (match_scratch:SI 3 "=&r"))
1150    (clobber (match_scratch:SI 4 "=1"))]
1151   "TARGET_ATOMIC_HARD_LLCS"
1153   return "\r    mov     #-4,%3"                 "\n"
1154          "      and     %1,%3"                  "\n"
1155          "      xor     %3,%1"                  "\n"
1156          "      add     r15,%1"                 "\n"
1157          "      add     #-4,%1"                 "\n"
1158          "0:    movli.l @%3,r0"                 "\n"
1159          "      mov.l   r0,@-r15"               "\n"
1160          "      mov.<bw>        @%1,r0"         "\n"
1161          "      and     %2,r0"                  "\n"
1162          "      not     r0,%0"                  "\n"
1163          "      mov.<bw>        %0,@%1"         "\n"
1164          "      mov.l   @r15+,r0"               "\n"
1165          "      movco.l r0,@%3"                 "\n"
1166          "      bf      0b";
1168   [(set_attr "length" "28")])
1170 (define_insn "atomic_nand_fetch<mode>_soft_gusa"
1171   [(set (match_operand:QIHISI 0 "register_operand" "=&u")
1172         (not:QIHISI (and:QIHISI
1173           (mem:QIHISI (match_operand:SI 1 "register_operand" "u"))
1174           (match_operand:QIHISI 2 "register_operand" "u"))))
1175    (set (mem:QIHISI (match_dup 1))
1176         (unspec:QIHISI
1177           [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
1178           UNSPEC_ATOMIC))
1179    (clobber (reg:SI R0_REG))
1180    (clobber (reg:SI R1_REG))]
1181   "TARGET_ATOMIC_SOFT_GUSA"
1183   return "\r    mova    1f,r0"                  "\n"
1184          "      .align 2"                       "\n"
1185          "      mov     r15,r1"                 "\n"
1186          "      mov     #(0f-1f),r15"           "\n"
1187          "0:    mov.<bwl>       @%1,%0"         "\n"
1188          "      and     %2,%0"                  "\n"
1189          "      not     %0,%0"                  "\n"
1190          "      mov.<bwl>       %0,@%1"         "\n"
1191          "1:    mov     r1,r15";
1193   [(set_attr "length" "18")])
1195 (define_insn "atomic_nand_fetch<mode>_soft_tcb"
1196   [(set (match_operand:QIHISI 0 "register_operand" "=&r")
1197         (not:QIHISI (and:QIHISI
1198           (mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
1199           (match_operand:QIHISI 2 "register_operand" "r"))))
1200    (set (mem:QIHISI (match_dup 1))
1201         (unspec:QIHISI
1202           [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
1203           UNSPEC_ATOMIC))
1204    (clobber (reg:SI R0_REG))
1205    (clobber (reg:SI R1_REG))
1206    (use (match_operand:SI 3 "gbr_displacement"))]
1207   "TARGET_ATOMIC_SOFT_TCB"
1209   return "\r    mova    1f,r0"                  "\n"
1210          "      mov     #(0f-1f),r1"            "\n"
1211          "      .align 2"                       "\n"
1212          "      mov.l   r0,@(%O3,gbr)"          "\n"
1213          "0:    mov.<bwl>       @%1,%0"         "\n"
1214          "      mov     #0,r0"                  "\n"
1215          "      and     %2,%0"                  "\n"
1216          "      not     %0,%0"                  "\n"
1217          "      mov.<bwl>       %0,@%1"         "\n"
1218          "1:    mov.l   r0,@(%O3,gbr)";
1220   [(set_attr "length" "20")])
1222 (define_insn "atomic_nand_fetch<mode>_soft_imask"
1223   [(set (match_operand:QIHISI 0 "register_operand" "=&z")
1224         (not:QIHISI (and:QIHISI
1225           (mem:QIHISI (match_operand:SI 1 "register_operand" "r"))
1226           (match_operand:QIHISI 2 "register_operand" "r"))))
1227    (set (mem:QIHISI (match_dup 1))
1228         (unspec:QIHISI
1229           [(not:QIHISI (and:QIHISI (mem:QIHISI (match_dup 1)) (match_dup 2)))]
1230           UNSPEC_ATOMIC))
1231    (clobber (match_scratch:SI 3 "=&r"))]
1232   "TARGET_ATOMIC_SOFT_IMASK"
1234   return "\r    stc     sr,%0"                  "\n"
1235          "      mov     %0,%3"                  "\n"
1236          "      or      #0xF0,%0"               "\n"
1237          "      ldc     %0,sr"                  "\n"
1238          "      mov.<bwl>       @%1,%0"         "\n"
1239          "      and     %2,%0"                  "\n"
1240          "      not     %0,%0"                  "\n"
1241          "      mov.<bwl>       %0,@%1"         "\n"
1242          "      ldc     %3,sr";
1244   [(set_attr "length" "18")])
1246 ;;------------------------------------------------------------------------------
1247 ;; read - test against zero - or with 0x80 - write - return test result
1249 (define_expand "atomic_test_and_set"
1250   [(match_operand:SI 0 "register_operand" "")           ;; bool result output
1251    (match_operand:QI 1 "memory_operand" "")             ;; memory
1252    (match_operand:SI 2 "const_int_operand" "")]         ;; model
1253   "(TARGET_ATOMIC_ANY || TARGET_ENABLE_TAS) && !TARGET_SHMEDIA"
1255   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
1257   if (TARGET_ENABLE_TAS)
1258     emit_insn (gen_tasb (addr));
1259   else
1260     {
1261       rtx val = gen_int_mode (targetm.atomic_test_and_set_trueval, QImode);
1262       val = force_reg (QImode, val);
1264       if (TARGET_ATOMIC_HARD_LLCS)
1265           emit_insn (gen_atomic_test_and_set_hard (addr, val));
1266       else if (TARGET_ATOMIC_SOFT_GUSA)
1267           emit_insn (gen_atomic_test_and_set_soft_gusa (addr, val));
1268       else if (TARGET_ATOMIC_SOFT_TCB)
1269           emit_insn (gen_atomic_test_and_set_soft_tcb (addr, val,
1270                          TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX));
1271       else if (TARGET_ATOMIC_SOFT_IMASK)
1272           emit_insn (gen_atomic_test_and_set_soft_imask (addr, val));
1273       else
1274         FAIL;
1275     }
1277   /* The result of the test op is the inverse of what we are
1278      supposed to return.  Thus invert the T bit.  The inversion will be
1279      potentially optimized away and integrated into surrounding code.  */
1280   emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ()));
1281   DONE;
1284 (define_insn "tasb"
1285   [(set (reg:SI T_REG)
1286         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1287                (const_int 0)))
1288    (set (mem:QI (match_dup 0))
1289         (unspec:QI [(const_int 128)] UNSPEC_ATOMIC))]
1290   "TARGET_ENABLE_TAS && !TARGET_SHMEDIA"
1291   "tas.b        @%0"
1292   [(set_attr "insn_class" "co_group")])
1294 (define_insn "atomic_test_and_set_soft_gusa"
1295   [(set (reg:SI T_REG)
1296         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "u"))
1297                (const_int 0)))
1298    (set (mem:QI (match_dup 0))
1299         (unspec:QI [(match_operand:QI 1 "register_operand" "u")] UNSPEC_ATOMIC))
1300    (clobber (match_scratch:QI 2 "=&u"))
1301    (clobber (reg:SI R0_REG))
1302    (clobber (reg:SI R1_REG))]
1303   "TARGET_ATOMIC_SOFT_GUSA && !TARGET_ENABLE_TAS"
1305   return "\r    mova    1f,r0"          "\n"
1306          "      .align 2"               "\n"
1307          "      mov     r15,r1"         "\n"
1308          "      mov     #(0f-1f),r15"   "\n"
1309          "0:    mov.b   @%0,%2"         "\n"
1310          "      mov.b   %1,@%0"         "\n"
1311          "1:    mov     r1,r15"         "\n"
1312          "      tst     %2,%2";
1314   [(set_attr "length" "16")])
1316 (define_insn "atomic_test_and_set_soft_tcb"
1317   [(set (reg:SI T_REG)
1318         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1319                (const_int 0)))
1320    (set (mem:QI (match_dup 0))
1321         (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
1322    (use (match_operand:SI 2 "gbr_displacement"))
1323    (clobber (match_scratch:QI 3 "=&r"))
1324    (clobber (reg:SI R0_REG))
1325    (clobber (reg:SI R1_REG))]
1326   "TARGET_ATOMIC_SOFT_TCB && !TARGET_ENABLE_TAS"
1328   return "\r    mova    1f,r0"          "\n"
1329          "      mov     #(0f-1f),r1"    "\n"
1330          "      .align 2"               "\n"
1331          "      mov.l   r0,@(%O2,gbr)"  "\n"
1332          "0:    mov.b   @%0,%3"         "\n"
1333          "      mov     #0,r0"          "\n"
1334          "      mov.b   %1,@%0"         "\n"
1335          "1:    mov.l   r0,@(%O2,gbr)"  "\n"
1336          "      tst     %3,%3";
1338   [(set_attr "length" "18")])
1340 (define_insn "atomic_test_and_set_soft_imask"
1341   [(set (reg:SI T_REG)
1342         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1343                (const_int 0)))
1344    (set (mem:QI (match_dup 0))
1345         (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
1346    (clobber (match_scratch:SI 2 "=&r"))
1347    (clobber (reg:SI R0_REG))]
1348   "TARGET_ATOMIC_SOFT_IMASK && !TARGET_ENABLE_TAS"
1350   return "\r    stc     sr,r0"          "\n"
1351          "      mov     r0,%2"          "\n"
1352          "      or      #0xF0,r0"       "\n"
1353          "      ldc     r0,sr"          "\n"
1354          "      mov.b   @%0,r0"         "\n"
1355          "      mov.b   %1,@%0"         "\n"
1356          "      stc     %2,sr"          "\n"
1357          "      tst     r0,r0";
1359   [(set_attr "length" "16")])
1361 (define_insn "atomic_test_and_set_hard"
1362   [(set (reg:SI T_REG)
1363         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
1364                (const_int 0)))
1365    (set (mem:QI (match_dup 0))
1366         (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
1367    (clobber (reg:SI R0_REG))
1368    (clobber (match_scratch:SI 2 "=&r"))
1369    (clobber (match_scratch:SI 3 "=&r"))
1370    (clobber (match_scratch:SI 4 "=0"))]
1371   "TARGET_ATOMIC_HARD_LLCS && !TARGET_ENABLE_TAS"
1373   return "\r    mov     #-4,%2"         "\n"
1374          "      and     %0,%2"          "\n"
1375          "      xor     %2,%0"          "\n"
1376          "      add     r15,%0"         "\n"
1377          "      add     #-4,%0"         "\n"
1378          "0:    movli.l @%2,r0"         "\n"
1379          "      mov.l   r0,@-r15"       "\n"
1380          "      mov.b   @%0,%3"         "\n"
1381          "      mov.b   %1,@%0"         "\n"
1382          "      mov.l   @r15+,r0"       "\n"
1383          "      movco.l r0,@%2"         "\n"
1384          "      bf      0b"             "\n"
1385          "      tst     %3,%3";
1387   [(set_attr "length" "26")])