Daily bump.
[official-gcc.git] / gcc / config / sh / sync.md
blob9dba513e64263ffa03434e90201c1107bec90652
1 ;; GCC machine description for SH synchronization instructions.
2 ;; Copyright (C) 2011-2018 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 ;;------------------------------------------------------------------------------
199 ;; comapre and swap
201 ;; Only the hard_llcs SImode patterns can use an I08 for the comparison
202 ;; or for the new swapped in value.
203 (define_predicate "atomic_arith_operand_0"
204   (and (match_code "subreg,reg,const_int")
205        (ior (match_operand 0 "arith_reg_operand")
206             (and (match_test "satisfies_constraint_I08 (op)")
207                  (match_test "mode == SImode")
208                  (ior (match_test "TARGET_ATOMIC_HARD_LLCS")
209                       (match_test "TARGET_ATOMIC_ANY && TARGET_SH4A
210                                    && !TARGET_ATOMIC_STRICT"))))))
212 ;; Displacement addressing can be used for all SImode atomic patterns, except
213 ;; llcs.
214 (define_predicate "atomic_mem_operand_0"
215   (and (match_code "mem")
216        (ior (match_operand 0 "simple_mem_operand")
217             (and (match_test "mode == SImode")
218                  (and (match_test "!TARGET_ATOMIC_HARD_LLCS")
219                       (match_test "!TARGET_SH4A || TARGET_ATOMIC_STRICT"))
220                  (match_operand 0 "short_displacement_mem_operand")))))
222 (define_expand "atomic_compare_and_swap<mode>"
223   [(match_operand:SI 0 "arith_reg_dest")                ;; bool success output
224    (match_operand:QIHISI 1 "arith_reg_dest")            ;; oldval output
225    (match_operand:QIHISI 2 "atomic_mem_operand_0")      ;; memory
226    (match_operand:QIHISI 3 "atomic_arith_operand_0")    ;; expected input
227    (match_operand:QIHISI 4 "atomic_arith_operand_0")    ;; newval input
228    (match_operand:SI 5 "const_int_operand")             ;; is_weak
229    (match_operand:SI 6 "const_int_operand")             ;; success model
230    (match_operand:SI 7 "const_int_operand")]            ;; failure model
231   "TARGET_ATOMIC_ANY"
233   rtx mem = operands[2];
234   rtx old_val = gen_lowpart (SImode, operands[1]);
235   rtx exp_val = operands[3];
236   rtx new_val = operands[4];
237   rtx atomic_insn;
239   if (TARGET_ATOMIC_HARD_LLCS
240       || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
241     atomic_insn = gen_atomic_compare_and_swap<mode>_hard (old_val, mem,
242                                                           exp_val, new_val);
243   else if (TARGET_ATOMIC_SOFT_GUSA)
244     atomic_insn = gen_atomic_compare_and_swap<mode>_soft_gusa (old_val, mem,
245                       exp_val, new_val);
246   else if (TARGET_ATOMIC_SOFT_TCB)
247     atomic_insn = gen_atomic_compare_and_swap<mode>_soft_tcb (old_val, mem,
248                       exp_val, new_val, TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
249   else if (TARGET_ATOMIC_SOFT_IMASK)
250     atomic_insn = gen_atomic_compare_and_swap<mode>_soft_imask (old_val, mem,
251                       exp_val, new_val);
252   else
253     FAIL;
255   emit_insn (atomic_insn);
257   if (<MODE>mode == QImode)
258     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[1]),
259                                      operands[1]));
260   else if (<MODE>mode == HImode)
261     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[1]),
262                                      operands[1]));
263   emit_insn (gen_movsi (operands[0], gen_rtx_REG (SImode, T_REG)));
264   DONE;
267 (define_insn_and_split "atomic_compare_and_swapsi_hard"
268   [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
269         (unspec_volatile:SI
270           [(match_operand:SI 1 "atomic_mem_operand_0" "=Sra")
271            (match_operand:SI 2 "arith_operand" "rI08")
272            (match_operand:SI 3 "arith_operand" "rI08")]
273           UNSPECV_CMPXCHG_1))
274    (set (match_dup 1)
275         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_2))
276    (set (reg:SI T_REG)
277         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
278    (clobber (reg:SI R0_REG))]
279   "TARGET_ATOMIC_HARD_LLCS
280    || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
282   return "\r0:  movli.l %1,r0"          "\n"
283          "      cmp/eq  %2,r0"          "\n"
284          "      bf{.|/}s        0f"     "\n"
285          "      mov     r0,%0"          "\n"
286          "      mov     %3,r0"          "\n"
287          "      movco.l r0,%1"          "\n"
288          "      bf      0b"             "\n"
289          "0:";
291   "&& can_create_pseudo_p () && !satisfies_constraint_I08 (operands[2])"
292   [(const_int 0)]
294   /* FIXME: Sometimes the 'expected value' operand is not propagated as
295      immediate value.  See PR 64974.  */
296   set_of_reg op2 = sh_find_set_of_reg (operands[2], curr_insn,
297                                        prev_nonnote_nondebug_insn_bb);
298   if (op2.set_src != NULL && satisfies_constraint_I08 (op2.set_src))
299     {
300       rtx* r = &XVECEXP (XEXP (XVECEXP (PATTERN (curr_insn), 0, 0), 1), 0, 1);
301       validate_change (curr_insn, r, op2.set_src, false);
302       DONE;
303     }
304   else
305     FAIL;
307   [(set_attr "length" "14")])
309 ;; The QIHImode llcs patterns modify the address register of the memory
310 ;; operand.  In order to express that, we have to open code the memory
311 ;; operand.  Initially the insn is expanded like every other atomic insn
312 ;; using the memory operand.  In split1 the insn is converted and the
313 ;; memory operand's address register is exposed.
314 (define_insn_and_split "atomic_compare_and_swap<mode>_hard"
315   [(set (match_operand:SI 0 "arith_reg_dest")
316         (unspec_volatile:SI
317           [(match_operand:QIHI 1 "atomic_mem_operand_0")
318            (match_operand:QIHI 2 "arith_reg_operand")
319            (match_operand:QIHI 3 "arith_reg_operand")]
320           UNSPECV_CMPXCHG_1))
321    (set (match_dup 1)
322         (unspec_volatile:QIHI [(const_int 0)] UNSPECV_CMPXCHG_2))
323    (set (reg:SI T_REG)
324         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
325    (clobber (reg:SI R0_REG))]
326   "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
327   "#"
328   "&& 1"
329   [(const_int 0)]
331   rtx i = gen_atomic_compare_and_swap<mode>_hard_1 (
332                 operands[0], XEXP (operands[1], 0), operands[2], operands[3]);
334   /* Replace the new mems in the new insn with the old mem to preserve
335      aliasing info.  */
336   XVECEXP (XEXP (XVECEXP (i, 0, 0), 1), 0, 0) = operands[1];
337   XEXP (XVECEXP (i, 0, 1), 0) = operands[1];
338   emit_insn (i);
341 (define_insn "atomic_compare_and_swap<mode>_hard_1"
342   [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
343         (unspec_volatile:SI
344           [(mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
345            (match_operand:QIHI 2 "arith_reg_operand" "r")
346            (match_operand:QIHI 3 "arith_reg_operand" "r")]
347           UNSPECV_CMPXCHG_1))
348    (set (mem:QIHI (match_dup 1))
349         (unspec_volatile:QIHI [(const_int 0)] UNSPECV_CMPXCHG_2))
350    (set (reg:SI T_REG)
351         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
352    (clobber (reg:SI R0_REG))
353    (clobber (match_scratch:SI 4 "=&r"))
354    (clobber (match_scratch:SI 5 "=&r"))
355    (clobber (match_scratch:SI 6 "=1"))]
356   "TARGET_ATOMIC_HARD_LLCS"
358   return "\r    mov     #-4,%5"                 "\n"
359          "      <i124extend_insn>       %2,%4"  "\n"
360          "      and     %1,%5"                  "\n"
361          "      xor     %5,%1"                  "\n"
362          "      add     r15,%1"                 "\n"
363          "      add     #-4,%1"                 "\n"
364          "0:    movli.l @%5,r0"                 "\n"
365          "      mov.l   r0,@-r15"               "\n"
366          "      mov.<bw>        @%1,%0"         "\n"
367          "      mov.<bw>        %3,@%1"         "\n"
368          "      cmp/eq  %4,%0"                  "\n"
369          "      bf{.|/}s        0f"             "\n"
370          "      mov.l   @r15+,r0"               "\n"
371          "      movco.l r0,@%5"                 "\n"
372          "      bf      0b"                     "\n"
373          "0:";
375   [(set_attr "length" "30")])
377 (define_insn "atomic_compare_and_swap<mode>_soft_gusa"
378   [(set (match_operand:SI 0 "arith_reg_dest" "=&u")
379         (unspec_volatile:SI
380           [(match_operand:QIHISI 1 "atomic_mem_operand_0" "=AraAdd")
381            (match_operand:QIHISI 2 "arith_reg_operand" "u")
382            (match_operand:QIHISI 3 "arith_reg_operand" "u")]
383           UNSPECV_CMPXCHG_1))
384    (set (match_dup 1)
385         (unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
386    (set (reg:SI T_REG)
387         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
388    (clobber (match_scratch:SI 4 "=&u"))
389    (clobber (reg:SI R0_REG))
390    (clobber (reg:SI R1_REG))]
391   "TARGET_ATOMIC_SOFT_GUSA"
393   return "\r    mova    1f,r0"                  "\n"
394          "      <i124extend_insn>       %2,%4"  "\n"
395          "      .align 2"                       "\n"
396          "      mov     r15,r1"                 "\n"
397          "      mov     #(0f-1f),r15"           "\n"
398          "0:    mov.<bwl>       %1,%0"          "\n"
399          "      cmp/eq  %0,%4"                  "\n"
400          "      bf      1f"                     "\n"
401          "      mov.<bwl>       %3,%1"          "\n"
402          "1:    mov     r1,r15";
404   [(set_attr "length" "20")])
406 (define_insn "atomic_compare_and_swap<mode>_soft_tcb"
407   [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
408         (unspec_volatile:SI
409           [(match_operand:QIHISI 1 "atomic_mem_operand_0" "=SraSdd")
410            (match_operand:QIHISI 2 "arith_reg_operand" "r")
411            (match_operand:QIHISI 3 "arith_reg_operand" "r")]
412           UNSPECV_CMPXCHG_1))
413    (set (match_dup 1)
414         (unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
415    (set (reg:SI T_REG)
416         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
417    (use (match_operand:SI 4 "gbr_displacement"))
418    (clobber (match_scratch:SI 5 "=&r"))
419    (clobber (reg:SI R0_REG))
420    (clobber (reg:SI R1_REG))]
421   "TARGET_ATOMIC_SOFT_TCB"
423   return "\r    mova    1f,r0"                  "\n"
424          "      .align 2"                       "\n"
425          "      <i124extend_insn>       %2,%5"  "\n"
426          "      mov     #(0f-1f),r1"            "\n"
427          "      mov.l   r0,@(%O4,gbr)"          "\n"
428          "0:    mov.<bwl>       %1,%0"          "\n"
429          "      mov     #0,r0"                  "\n"
430          "      cmp/eq  %0,%5"                  "\n"
431          "      bf      1f"                     "\n"
432          "      mov.<bwl>       %3,%1"          "\n"
433          "1:    mov.l   r0,@(%O4,gbr)";
435   [(set_attr "length" "22")])
437 (define_insn "atomic_compare_and_swap<mode>_soft_imask"
438   [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
439         (unspec_volatile:SI
440           [(match_operand:QIHISI 1 "atomic_mem_operand_0" "=SraSdd")
441            (match_operand:QIHISI 2 "arith_reg_operand" "r")
442            (match_operand:QIHISI 3 "arith_reg_operand" "r")]
443           UNSPECV_CMPXCHG_1))
444    (set (match_dup 1)
445         (unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2))
446    (set (reg:SI T_REG)
447         (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
448    (clobber (match_scratch:SI 4 "=&r"))
449    (clobber (match_scratch:SI 5 "=&r"))]
450   "TARGET_ATOMIC_SOFT_IMASK"
452   /* The comparison result is supposed to be in T_REG.
453      Notice that restoring SR will overwrite the T_REG.  We handle this by
454      rotating the T_REG into the saved SR before restoring SR.  On SH2A we
455      can do one insn shorter by using the bst insn.  */
456   if (!TARGET_SH2A)
457     return "\r  stc     sr,%0"                  "\n"
458            "    <i124extend_insn>       %2,%4"  "\n"
459            "    mov     %0,%5"                  "\n"
460            "    or      #0xF0,%0"               "\n"
461            "    shlr    %5"                     "\n"
462            "    ldc     %0,sr"                  "\n"
463            "    mov.<bwl>       %1,%0"          "\n"
464            "    cmp/eq  %4,%0"                  "\n"
465            "    bf      1f"                     "\n"
466            "    mov.<bwl>       %3,%1"          "\n"
467            "1:  rotcl   %5"                     "\n"
468            "    ldc     %5,sr";
469   else
470     return "\r  stc     sr,%0"                  "\n"
471            "    <i124extend_insn>       %2,%4"  "\n"
472            "    mov     %0,%5"                  "\n"
473            "    or      #0xF0,%0"               "\n"
474            "    ldc     %0,sr"                  "\n"
475            "    mov.<bwl>       %1,%0"          "\n"
476            "    cmp/eq  %4,%0"                  "\n"
477            "    bst     #0,%5"                  "\n"
478            "    bf      1f"                     "\n"
479            "    mov.<bwl>       %3,%1"          "\n"
480            "1:  ldc     %5,sr";
482   [(set (attr "length") (if_then_else (match_test "!TARGET_SH2A")
483                                       (const_string "24")
484                                       (const_string "22")))])
486 ;;------------------------------------------------------------------------------
487 ;; read - write - return old value
489 (define_expand "atomic_exchange<mode>"
490   [(match_operand:QIHISI 0 "arith_reg_dest")            ;; oldval output
491    (match_operand:QIHISI 1 "atomic_mem_operand_0")      ;; memory
492    (match_operand:QIHISI 2 "atomic_arith_operand_0")    ;; newval input
493    (match_operand:SI 3 "const_int_operand")]            ;; memory model
494   "TARGET_ATOMIC_ANY"
496   rtx mem = operands[1];
497   rtx val = operands[2];
498   rtx atomic_insn;
500   if (TARGET_ATOMIC_HARD_LLCS
501       || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
502     atomic_insn = gen_atomic_exchange<mode>_hard (operands[0], mem, val);
503   else if (TARGET_ATOMIC_SOFT_GUSA)
504     atomic_insn = gen_atomic_exchange<mode>_soft_gusa (operands[0], mem, val);
505   else if (TARGET_ATOMIC_SOFT_TCB)
506     atomic_insn = gen_atomic_exchange<mode>_soft_tcb (operands[0], mem, val,
507                       TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
508   else if (TARGET_ATOMIC_SOFT_IMASK)
509     atomic_insn = gen_atomic_exchange<mode>_soft_imask (operands[0], mem, val);
510   else
511     FAIL;
513   emit_insn (atomic_insn);
515   if (<MODE>mode == QImode)
516     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
517                                      operands[0]));
518   else if (<MODE>mode == HImode)
519     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
520                                      operands[0]));
521   DONE;
524 (define_insn "atomic_exchangesi_hard"
525   [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
526         (match_operand:SI 1 "atomic_mem_operand_0" "=Sra"))
527    (set (match_dup 1)
528         (unspec:SI
529           [(match_operand:SI 2 "arith_operand" "rI08")] UNSPEC_ATOMIC))
530    (set (reg:SI T_REG) (const_int 1))
531    (clobber (reg:SI R0_REG))]
532   "TARGET_ATOMIC_HARD_LLCS
533    || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
535   return "\r0:  movli.l %1,r0"          "\n"
536          "      mov     r0,%0"          "\n"
537          "      mov     %2,r0"          "\n"
538          "      movco.l r0,%1"          "\n"
539          "      bf      0b";
541   [(set_attr "length" "10")])
543 ;; The QIHImode llcs patterns modify the address register of the memory
544 ;; operand.  In order to express that, we have to open code the memory
545 ;; operand.  Initially the insn is expanded like every other atomic insn
546 ;; using the memory operand.  In split1 the insn is converted and the
547 ;; memory operand's address register is exposed.
548 (define_insn_and_split "atomic_exchange<mode>_hard"
549   [(set (match_operand:QIHI 0 "arith_reg_dest")
550         (match_operand:QIHI 1 "atomic_mem_operand_0"))
551    (set (match_dup 1)
552         (unspec:QIHI
553           [(match_operand:QIHI 2 "arith_reg_operand")] UNSPEC_ATOMIC))
554    (set (reg:SI T_REG) (const_int 1))
555    (clobber (reg:SI R0_REG))]
556   "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
557   "#"
558   "&& 1"
559   [(const_int 0)]
561   rtx i = gen_atomic_exchange<mode>_hard_1 (operands[0], XEXP (operands[1], 0),
562                                             operands[2]);
564   /* Replace the new mems in the new insn with the old mem to preserve
565      aliasing info.  */
566   XEXP (XVECEXP (i, 0, 0), 1) = operands[1];
567   XEXP (XVECEXP (i, 0, 1), 0) = operands[1];
568   emit_insn (i);
571 (define_insn "atomic_exchange<mode>_hard_1"
572   [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
573         (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
574    (set (mem:QIHI (match_dup 1))
575         (unspec:QIHI
576           [(match_operand:QIHI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC))
577    (set (reg:SI T_REG) (const_int 1))
578    (clobber (reg:SI R0_REG))
579    (clobber (match_scratch:SI 3 "=&r"))
580    (clobber (match_scratch:SI 4 "=1"))]
581   "TARGET_ATOMIC_HARD_LLCS"
583   return "\r    mov     #-4,%3"                 "\n"
584          "      and     %1,%3"                  "\n"
585          "      xor     %3,%1"                  "\n"
586          "      add     r15,%1"                 "\n"
587          "      add     #-4,%1"                 "\n"
588          "0:    movli.l @%3,r0"                 "\n"
589          "      mov.l   r0,@-r15"               "\n"
590          "      mov.<bw>        @%1,%0"         "\n"
591          "      mov.<bw>        %2,@%1"         "\n"
592          "      mov.l   @r15+,r0"               "\n"
593          "      movco.l r0,@%3"                 "\n"
594          "      bf      0b";
596   [(set_attr "length" "24")])
598 (define_insn "atomic_exchange<mode>_soft_gusa"
599   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
600         (match_operand:QIHISI 1 "atomic_mem_operand_0" "=AraAdd"))
601    (set (match_dup 1)
602         (unspec:QIHISI
603           [(match_operand:QIHISI 2 "arith_reg_operand" "u")] UNSPEC_ATOMIC))
604    (clobber (reg:SI R0_REG))
605    (clobber (reg:SI R1_REG))]
606   "TARGET_ATOMIC_SOFT_GUSA"
608   return "\r    mova    1f,r0"                  "\n"
609          "      .align 2"                       "\n"
610          "      mov     r15,r1"                 "\n"
611          "      mov     #(0f-1f),r15"           "\n"
612          "0:    mov.<bwl>       %1,%0"          "\n"
613          "      mov.<bwl>       %2,%1"          "\n"
614          "1:    mov     r1,r15";
616   [(set_attr "length" "14")])
618 (define_insn "atomic_exchange<mode>_soft_tcb"
619   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
620         (match_operand:QIHISI 1 "atomic_mem_operand_0" "=SraSdd"))
621    (set (match_dup 1)
622         (unspec:QIHISI
623           [(match_operand:QIHISI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC))
624    (clobber (reg:SI R0_REG))
625    (clobber (reg:SI R1_REG))
626    (use (match_operand:SI 3 "gbr_displacement"))]
627   "TARGET_ATOMIC_SOFT_TCB"
629   return "\r    mova    1f,r0"                  "\n"
630          "      mov     #(0f-1f),r1"            "\n"
631          "      .align 2"                       "\n"
632          "      mov.l   r0,@(%O3,gbr)"          "\n"
633          "0:    mov.<bwl>       %1,%0"          "\n"
634          "      mov     #0,r0"                  "\n"
635          "      mov.<bwl>       %2,%1"          "\n"
636          "1:    mov.l   r0,@(%O3,gbr)";
638   [(set_attr "length" "16")])
640 (define_insn "atomic_exchange<mode>_soft_imask"
641   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
642         (match_operand:QIHISI 1 "atomic_mem_operand_0" "=SraSdd"))
643    (set (match_dup 1)
644         (unspec:QIHISI
645           [(match_operand:QIHISI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC))
646    (clobber (match_scratch:SI 3 "=&r"))]
647   "TARGET_ATOMIC_SOFT_IMASK"
649   return "\r    stc     sr,%0"                  "\n"
650          "      mov     %0,%3"                  "\n"
651          "      or      #0xF0,%0"               "\n"
652          "      ldc     %0,sr"                  "\n"
653          "      mov.<bwl>       %1,%0"          "\n"
654          "      mov.<bwl>       %2,%1"          "\n"
655          "      ldc     %3,sr";
657   [(set_attr "length" "14")])
659 ;;------------------------------------------------------------------------------
660 ;; read - add|sub|or|and|xor|nand - write - return old value
662 ;; atomic_arith_operand_1 can be used by any atomic type for a plus op,
663 ;; since there's no r0 restriction.
664 (define_predicate "atomic_arith_operand_1"
665   (and (match_code "subreg,reg,const_int")
666        (ior (match_operand 0 "arith_reg_operand")
667             (match_test "satisfies_constraint_I08 (op)"))))
669 ;; atomic_logic_operand_1 can be used by the hard_llcs, tcb and soft_imask
670 ;; patterns only due to its r0 restriction. 
671 (define_predicate "atomic_logical_operand_1"
672   (and (match_code "subreg,reg,const_int")
673        (ior (match_operand 0 "arith_reg_operand")
674             (and (match_test "satisfies_constraint_K08 (op)")
675                  (ior (match_test "TARGET_ATOMIC_HARD_LLCS")
676                       (match_test "TARGET_ATOMIC_SOFT_IMASK")
677                       (match_test "TARGET_ATOMIC_SOFT_TCB")
678                       (match_test "TARGET_ATOMIC_ANY && TARGET_SH4A
679                                    && mode == SImode
680                                    && !TARGET_ATOMIC_STRICT"))))))
682 (define_code_attr fetchop_predicate_1
683   [(plus "atomic_arith_operand_1") (minus "arith_reg_operand")
684    (ior "atomic_logical_operand_1") (xor "atomic_logical_operand_1")
685    (and "atomic_logical_operand_1")])
687 (define_code_attr fetchop_constraint_1_llcs
688   [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
690 (define_code_attr fetchop_constraint_1_gusa
691   [(plus "uI08") (minus "u") (ior "u") (xor "u") (and "u")])
693 (define_code_attr fetchop_constraint_1_tcb
694   [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
696 (define_code_attr fetchop_constraint_1_imask
697   [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")])
699 ;; Displacement addressing mode (incl. GBR relative) can be used by tcb and
700 ;; imask atomic patterns in any mode, since all the patterns use R0 as the
701 ;; register operand for memory loads/stores.  gusa and llcs patterns can only
702 ;; use displacement addressing for SImode.
703 (define_predicate "atomic_mem_operand_1"
704   (and (match_code "mem")
705        (ior (match_operand 0 "simple_mem_operand")
706             (and (match_test "mode == SImode")
707                  (match_test "TARGET_ATOMIC_SOFT_GUSA
708                               && (!TARGET_SH4A || TARGET_ATOMIC_STRICT)")
709                  (match_operand 0 "short_displacement_mem_operand"))
710             (and (ior (match_test "(TARGET_ATOMIC_SOFT_TCB
711                                     || TARGET_ATOMIC_SOFT_IMASK)
712                                    && (!TARGET_SH4A || TARGET_ATOMIC_STRICT)")
713                       (match_test "(TARGET_ATOMIC_SOFT_TCB
714                                     || TARGET_ATOMIC_SOFT_IMASK)
715                                    && TARGET_SH4A && !TARGET_ATOMIC_STRICT
716                                    && mode != SImode"))
717                  (ior (match_operand 0 "short_displacement_mem_operand")
718                       (match_operand 0 "gbr_address_mem"))))))
720 (define_expand "atomic_fetch_<fetchop_name><mode>"
721   [(set (match_operand:QIHISI 0 "arith_reg_dest")
722         (match_operand:QIHISI 1 "atomic_mem_operand_1"))
723    (set (match_dup 1)
724         (unspec:QIHISI
725           [(FETCHOP:QIHISI (match_dup 1)
726              (match_operand:QIHISI 2 "<fetchop_predicate_1>"))]
727           UNSPEC_ATOMIC))
728    (match_operand:SI 3 "const_int_operand")]
729   "TARGET_ATOMIC_ANY"
731   rtx mem = operands[1];
732   rtx atomic_insn;
734   if (TARGET_ATOMIC_HARD_LLCS
735       || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
736     atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_hard (operands[0], mem,
737                                                               operands[2]);
738   else if (TARGET_ATOMIC_SOFT_GUSA)
739     atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_gusa (operands[0],
740                       mem, operands[2]);
741   else if (TARGET_ATOMIC_SOFT_TCB)
742     atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_tcb (operands[0],
743                       mem, operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
744   else if (TARGET_ATOMIC_SOFT_IMASK)
745     atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_imask (operands[0],
746                       mem, operands[2]);
747   else
748     FAIL;
750   emit_insn (atomic_insn);
752   if (<MODE>mode == QImode)
753     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
754                                      operands[0]));
755   else if (<MODE>mode == HImode)
756     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
757                                      operands[0]));
758   DONE;
761 (define_insn_and_split "atomic_fetch_<fetchop_name>si_hard"
762   [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
763         (match_operand:SI 1 "atomic_mem_operand_1" "=Sra"))
764    (set (match_dup 1)
765         (unspec:SI
766           [(FETCHOP:SI (match_dup 1)
767                        (match_operand:SI 2 "<fetchop_predicate_1>"
768                                            "<fetchop_constraint_1_llcs>"))]
769           UNSPEC_ATOMIC))
770    (set (reg:SI T_REG) (const_int 1))
771    (clobber (reg:SI R0_REG))]
772   "TARGET_ATOMIC_HARD_LLCS
773    || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
775   return "\r0:  movli.l %1,r0"          "\n"
776          "      mov     r0,%0"          "\n"
777          "      <fetchop_name>  %2,r0"  "\n"
778          "      movco.l r0,%1"          "\n"
779          "      bf      0b";
781   "&& can_create_pseudo_p () && optimize
782    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
783   [(const_int 0)]
785   emit_insn (gen_atomic_<fetchop_name>_fetchsi_hard (gen_reg_rtx (SImode),
786                                                      operands[1], operands[2]));
788   [(set_attr "length" "10")])
790 ;; Combine pattern for xor (val, -1) / nand (val, -1).
791 (define_insn_and_split "atomic_fetch_notsi_hard"
792   [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
793         (match_operand:SI 1 "atomic_mem_operand_1" "=Sra"))
794    (set (match_dup 1)
795         (unspec:SI [(not:SI (match_dup 1))] UNSPEC_ATOMIC))
796    (set (reg:SI T_REG) (const_int 1))
797    (clobber (reg:SI R0_REG))]
798   "TARGET_ATOMIC_HARD_LLCS
799    || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
801   return "\r0:  movli.l %1,r0"          "\n"
802          "      mov     r0,%0"          "\n"
803          "      not     r0,r0"          "\n"
804          "      movco.l r0,%1"          "\n"
805          "      bf      0b";
807   "&& can_create_pseudo_p () && optimize
808    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
809   [(const_int 0)]
811   emit_insn (gen_atomic_not_fetchsi_hard (gen_reg_rtx (SImode), operands[1]));
813   [(set_attr "length" "10")])
815 ;; The QIHImode llcs patterns modify the address register of the memory
816 ;; operand.  In order to express that, we have to open code the memory
817 ;; operand.  Initially the insn is expanded like every other atomic insn
818 ;; using the memory operand.  In split1 the insn is converted and the
819 ;; memory operand's address register is exposed.
820 (define_insn_and_split "atomic_fetch_<fetchop_name><mode>_hard"
821   [(set (match_operand:QIHI 0 "arith_reg_dest")
822         (match_operand:QIHI 1 "atomic_mem_operand_1"))
823    (set (match_dup 1)
824         (unspec:QIHI
825           [(FETCHOP:QIHI (match_dup 1)
826                          (match_operand:QIHI 2 "<fetchop_predicate_1>"))]
827           UNSPEC_ATOMIC))
828    (set (reg:SI T_REG) (const_int 1))
829    (clobber (reg:SI R0_REG))]
830   "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
831   "#"
832   "&& 1"
833   [(const_int 0)]
835   if (optimize
836       && sh_reg_dead_or_unused_after_insn (curr_insn, REGNO (operands[0])))
837     emit_insn (gen_atomic_<fetchop_name><mode>_hard (operands[1], operands[2]));
838   else
839     {
840       rtx i = gen_atomic_fetch_<fetchop_name><mode>_hard_1 (
841                         operands[0], XEXP (operands[1], 0), operands[2]);
843       /* Replace the new mems in the new insn with the old mem to preserve
844          aliasing info.  */
845       XEXP (XVECEXP (i, 0, 0), 1) = operands[1];
846       XEXP (XVECEXP (i, 0, 1), 0) = operands[1];
847       XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 1), 1), 0, 0), 0) = operands[1];
848       emit_insn (i);
849     }
852 (define_insn "atomic_fetch_<fetchop_name><mode>_hard_1"
853   [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
854         (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
855    (set (mem:QIHI (match_dup 1))
856         (unspec:QIHI
857           [(FETCHOP:QIHI (mem:QIHI (match_dup 1))
858                          (match_operand:QIHI 2 "<fetchop_predicate_1>"
859                                                "<fetchop_constraint_1_llcs>"))]
860           UNSPEC_ATOMIC))
861    (set (reg:SI T_REG) (const_int 1))
862    (clobber (reg:SI R0_REG))
863    (clobber (match_scratch:SI 3 "=&r"))
864    (clobber (match_scratch:SI 4 "=1"))]
865   "TARGET_ATOMIC_HARD_LLCS"
867   return "\r    mov     #-4,%3"                 "\n"
868          "      and     %1,%3"                  "\n"
869          "      xor     %3,%1"                  "\n"
870          "      add     r15,%1"                 "\n"
871          "      add     #-4,%1"                 "\n"
872          "0:    movli.l @%3,r0"                 "\n"
873          "      mov.l   r0,@-r15"               "\n"
874          "      mov.<bw>        @%1,r0"         "\n"
875          "      mov     r0,%0"                  "\n"
876          "      <fetchop_name>  %2,r0"          "\n"
877          "      mov.<bw>        r0,@%1"         "\n"
878          "      mov.l   @r15+,r0"               "\n"
879          "      movco.l r0,@%3"                 "\n"
880          "      bf      0b";
882   [(set_attr "length" "28")])
884 ;; The QIHImode llcs patterns modify the address register of the memory
885 ;; operand.  In order to express that, we have to open code the memory
886 ;; operand.  Initially the insn is expanded like every other atomic insn
887 ;; using the memory operand.  In split1 the insn is converted and the
888 ;; memory operand's address register is exposed.
889 (define_insn_and_split "atomic_<fetchop_name><mode>_hard"
890   [(set (match_operand:QIHI 0 "atomic_mem_operand_1")
891         (unspec:QIHI
892           [(FETCHOP:QIHI (match_dup 0)
893                          (match_operand:QIHI 1 "<fetchop_predicate_1>"))]
894           UNSPEC_ATOMIC))
895    (set (reg:SI T_REG) (const_int 1))
896    (clobber (reg:SI R0_REG))]
897   "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
898   "#"
899   "&& 1"
900   [(const_int 0)]
902   rtx i = gen_atomic_<fetchop_name><mode>_hard_1 (XEXP (operands[0], 0),
903                                                   operands[1]);
904   /* Replace the new mems in the new insn with the old mem to preserve
905      aliasing info.  */
906   XEXP (XVECEXP (i, 0, 0), 0) = operands[0];
907   XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 0), 1), 0, 0), 0) = operands[0];
908   emit_insn (i);
911 (define_insn "atomic_<fetchop_name><mode>_hard_1"
912   [(set (mem:QIHI (match_operand:SI 0 "arith_reg_operand" "r"))
913         (unspec:QIHI
914           [(FETCHOP:QIHI (mem:QIHI (match_dup 0))
915                          (match_operand:QIHI 1 "<fetchop_predicate_1>"
916                                                "<fetchop_constraint_1_llcs>"))]
917           UNSPEC_ATOMIC))
918    (set (reg:SI T_REG) (const_int 1))
919    (clobber (reg:SI R0_REG))
920    (clobber (match_scratch:SI 2 "=&r"))
921    (clobber (match_scratch:SI 3 "=0"))]
922   "TARGET_ATOMIC_HARD_LLCS"
924   return "\r    mov     #-4,%2"                 "\n"
925          "      and     %0,%2"                  "\n"
926          "      xor     %2,%0"                  "\n"
927          "      add     r15,%0"                 "\n"
928          "      add     #-4,%0"                 "\n"
929          "0:    movli.l @%2,r0"                 "\n"
930          "      mov.l   r0,@-r15"               "\n"
931          "      mov.<bw>        @%0,r0"         "\n"
932          "      <fetchop_name>  %1,r0"          "\n"
933          "      mov.<bw>        r0,@%0"         "\n"
934          "      mov.l   @r15+,r0"               "\n"
935          "      movco.l r0,@%2"                 "\n"
936          "      bf      0b";
938   [(set_attr "length" "26")])
940 ;; Combine pattern for xor (val, -1) / nand (val, -1).
941 (define_insn_and_split "atomic_fetch_not<mode>_hard"
942   [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
943         (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
944    (set (mem:QIHI (match_dup 1))
945         (unspec:QIHI [(not:QIHI (mem:QIHI (match_dup 1)))] UNSPEC_ATOMIC))
946    (set (reg:SI T_REG) (const_int 1))
947    (clobber (reg:SI R0_REG))
948    (clobber (match_scratch:SI 2 "=&r"))
949    (clobber (match_scratch:SI 3 "=1"))]
950   "TARGET_ATOMIC_HARD_LLCS"
952   return "\r    mov     #-4,%2"                 "\n"
953          "      and     %1,%2"                  "\n"
954          "      xor     %2,%1"                  "\n"
955          "      add     r15,%1"                 "\n"
956          "      add     #-4,%1"                 "\n"
957          "0:    movli.l @%2,r0"                 "\n"
958          "      mov.l   r0,@-r15"               "\n"
959          "      mov.<bw>        @%1,%0"         "\n"
960          "      not     %0,r0"                  "\n"
961          "      mov.<bw>        r0,@%1"         "\n"
962          "      mov.l   @r15+,r0"               "\n"
963          "      movco.l r0,@%2"                 "\n"
964          "      bf      0b";
966   "&& can_create_pseudo_p () && optimize
967    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
968   [(const_int 0)]
970   rtx i = gen_atomic_not<mode>_hard (operands[1]);
972   /* Replace the new mems in the new insn with the old mem to preserve
973      aliasing info.  */
974   rtx m = XEXP (XVECEXP (PATTERN (curr_insn), 0, 0), 1);
975   XEXP (XVECEXP (i, 0, 0), 0) = m;
976   XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 0), 1), 0, 0), 0) = m;
977   emit_insn (i);
979   [(set_attr "length" "26")])
981 (define_insn "atomic_not<mode>_hard"
982   [(set (mem:QIHI (match_operand:SI 0 "arith_reg_operand" "r"))
983         (unspec:QIHI [(not:QIHI (mem:QIHI (match_dup 0)))] UNSPEC_ATOMIC))
984    (set (reg:SI T_REG) (const_int 1))
985    (clobber (reg:SI R0_REG))
986    (clobber (match_scratch:SI 1 "=&r"))
987    (clobber (match_scratch:SI 2 "=0"))]
988   "TARGET_ATOMIC_HARD_LLCS"
990   return "\r    mov     #-4,%1"                 "\n"
991          "      and     %0,%1"                  "\n"
992          "      xor     %1,%0"                  "\n"
993          "      add     r15,%0"                 "\n"
994          "      add     #-4,%0"                 "\n"
995          "0:    movli.l @%1,r0"                 "\n"
996          "      mov.l   r0,@-r15"               "\n"
997          "      mov.<bw>        @%0,r0"         "\n"
998          "      not     r0,r0"                  "\n"
999          "      mov.<bw>        r0,@%0"         "\n"
1000          "      mov.l   @r15+,r0"               "\n"
1001          "      movco.l r0,@%1"                 "\n"
1002          "      bf      0b";
1004   [(set_attr "length" "26")])
1006 (define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_gusa"
1007   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1008         (match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd"))
1009    (set (match_dup 1)
1010         (unspec:QIHISI
1011           [(FETCHOP:QIHISI
1012                 (match_dup 1)
1013                 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1014                                         "<fetchop_constraint_1_gusa>"))]
1015           UNSPEC_ATOMIC))
1016    (clobber (match_scratch:QIHISI 3 "=&u"))
1017    (clobber (reg:SI R0_REG))
1018    (clobber (reg:SI R1_REG))]
1019   "TARGET_ATOMIC_SOFT_GUSA"
1021   return "\r    mova    1f,r0"                  "\n"
1022          "      .align 2"                       "\n"
1023          "      mov     r15,r1"                 "\n"
1024          "      mov     #(0f-1f),r15"           "\n"
1025          "0:    mov.<bwl>       %1,%0"          "\n"
1026          "      mov     %0,%3"                  "\n"
1027          "      <fetchop_name>  %2,%3"          "\n"
1028          "      mov.<bwl>       %3,%1"          "\n"
1029          "1:    mov     r1,r15";
1031   "&& can_create_pseudo_p () && optimize
1032    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1033   [(const_int 0)]
1035   emit_insn (gen_atomic_<fetchop_name>_fetch<mode>_soft_gusa (
1036                 gen_reg_rtx (<MODE>mode), operands[1], operands[2]));
1038   [(set_attr "length" "18")])
1040 ;; Combine pattern for xor (val, -1) / nand (val, -1).
1041 (define_insn_and_split "atomic_fetch_not<mode>_soft_gusa"
1042   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1043         (match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd"))
1044    (set (match_dup 1)
1045         (unspec:QIHISI [(not:QIHISI (match_dup 1))] UNSPEC_ATOMIC))
1046    (clobber (match_scratch:QIHISI 2 "=&u"))
1047    (clobber (reg:SI R0_REG))
1048    (clobber (reg:SI R1_REG))]
1049   "TARGET_ATOMIC_SOFT_GUSA"
1051   return "\r    mova    1f,r0"                  "\n"
1052          "      mov     r15,r1"                 "\n"
1053          "      .align 2"                       "\n"
1054          "      mov     #(0f-1f),r15"           "\n"
1055          "0:    mov.<bwl>       %1,%0"          "\n"
1056          "      not     %0,%2"                  "\n"
1057          "      mov.<bwl>       %2,%1"          "\n"
1058          "1:    mov     r1,r15";
1060   "&& can_create_pseudo_p () && optimize
1061    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1062   [(const_int 0)]
1064   emit_insn (gen_atomic_not_fetch<mode>_soft_gusa (gen_reg_rtx (<MODE>mode),
1065                                                    operands[1]));
1067   [(set_attr "length" "16")])
1069 (define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_tcb"
1070   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1071         (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd"))
1072    (set (match_dup 1)
1073         (unspec:QIHISI
1074           [(FETCHOP:QIHISI
1075                 (match_dup 1)
1076                 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1077                                         "<fetchop_constraint_1_tcb>"))]
1078           UNSPEC_ATOMIC))
1079    (use (match_operand:SI 3 "gbr_displacement"))
1080    (clobber (reg:SI R0_REG))
1081    (clobber (reg:SI R1_REG))]
1082   "TARGET_ATOMIC_SOFT_TCB"
1084   return "\r    mova    1f,r0"                  "\n"
1085          "      .align 2"                       "\n"
1086          "      mov     #(0f-1f),r1"            "\n"
1087          "      mov.l   r0,@(%O3,gbr)"          "\n"
1088          "0:    mov.<bwl>       %1,r0"          "\n"
1089          "      mov     r0,%0"                  "\n"
1090          "      <fetchop_name>  %2,r0"          "\n"
1091          "      mov.<bwl>       r0,%1"          "\n"
1092          "1:    mov     #0,r0"                  "\n"
1093          "      mov.l   r0,@(%O3,gbr)";
1095   "&& can_create_pseudo_p () && optimize
1096    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1097   [(const_int 0)]
1099   emit_insn (gen_atomic_<fetchop_name><mode>_soft_tcb (
1100                                         operands[1], operands[2], operands[3]));
1102   [(set_attr "length" "20")])
1104 (define_insn "atomic_<fetchop_name><mode>_soft_tcb"
1105   [(set (match_operand:QIHISI 0 "atomic_mem_operand_1" "=SraSdd")
1106         (unspec:QIHISI
1107           [(FETCHOP:QIHISI
1108                 (match_dup 0)
1109                 (match_operand:QIHISI 1 "<fetchop_predicate_1>"
1110                                         "<fetchop_constraint_1_tcb>"))]
1111           UNSPEC_ATOMIC))
1112    (use (match_operand:SI 2 "gbr_displacement"))
1113    (clobber (reg:SI R0_REG))
1114    (clobber (reg:SI R1_REG))]
1115   "TARGET_ATOMIC_SOFT_TCB"
1117   return "\r    mova    1f,r0"                  "\n"
1118          "      mov     #(0f-1f),r1"            "\n"
1119          "      .align 2"                       "\n"
1120          "      mov.l   r0,@(%O2,gbr)"          "\n"
1121          "0:    mov.<bwl>       %0,r0"          "\n"
1122          "      <fetchop_name>  %1,r0"          "\n"
1123          "      mov.<bwl>       r0,%0"          "\n"
1124          "1:    mov     #0,r0"                  "\n"
1125          "      mov.l   r0,@(%O2,gbr)";
1127   [(set_attr "length" "18")])
1129 ;; Combine pattern for xor (val, -1) / nand (val, -1).
1130 (define_insn_and_split "atomic_fetch_not<mode>_soft_tcb"
1131   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1132         (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd"))
1133    (set (match_dup 1)
1134         (unspec:QIHISI [(not:QIHISI (match_dup 1))] UNSPEC_ATOMIC))
1135    (use (match_operand:SI 2 "gbr_displacement"))
1136    (clobber (reg:SI R0_REG))
1137    (clobber (reg:SI R1_REG))]
1138   "TARGET_ATOMIC_SOFT_TCB"
1140   return "\r    mova    1f,r0"                  "\n"
1141          "      .align 2"                       "\n"
1142          "      mov     #(0f-1f),r1"            "\n"
1143          "      mov.l   r0,@(%O2,gbr)"          "\n"
1144          "0:    mov.<bwl>       %1,r0"          "\n"
1145          "      mov     r0,%0"                  "\n"
1146          "      not     r0,r0"                  "\n"
1147          "      mov.<bwl>       r0,%1"          "\n"
1148          "1:    mov     #0,r0"                  "\n"
1149          "      mov.l   r0,@(%O2,gbr)";
1151   "&& can_create_pseudo_p () && optimize
1152    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1153   [(const_int 0)]
1155   emit_insn (gen_atomic_not<mode>_soft_tcb (operands[1], operands[2]));
1157   [(set_attr "length" "20")])
1159 (define_insn "atomic_not<mode>_soft_tcb"
1160   [(set (match_operand:QIHISI 0 "atomic_mem_operand_1" "=SraSdd")
1161         (unspec:QIHISI [(not:QIHISI (match_dup 0))] UNSPEC_ATOMIC))
1162    (use (match_operand:SI 1 "gbr_displacement"))
1163    (clobber (reg:SI R0_REG))
1164    (clobber (reg:SI R1_REG))]
1165   "TARGET_ATOMIC_SOFT_TCB"
1167   return "\r    mova    1f,r0"                  "\n"
1168          "      mov     #(0f-1f),r1"            "\n"
1169          "      .align 2"                       "\n"
1170          "      mov.l   r0,@(%O1,gbr)"          "\n"
1171          "0:    mov.<bwl>       %0,r0"          "\n"
1172          "      not     r0,r0"                  "\n"
1173          "      mov.<bwl>       r0,%0"          "\n"
1174          "1:    mov     #0,r0"                  "\n"
1175          "      mov.l   r0,@(%O1,gbr)";
1177   [(set_attr "length" "18")])
1179 (define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_imask"
1180   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1181         (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd"))
1182    (set (match_dup 1)
1183         (unspec:QIHISI
1184           [(FETCHOP:QIHISI
1185                 (match_dup 1)
1186                 (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1187                                         "<fetchop_constraint_1_imask>"))]
1188           UNSPEC_ATOMIC))
1189    (clobber (reg:SI R0_REG))
1190    (clobber (match_scratch:QIHISI 3 "=&r"))]
1191   "TARGET_ATOMIC_SOFT_IMASK"
1193   return "\r    stc     sr,r0"                  "\n"
1194          "      mov     r0,%3"                  "\n"
1195          "      or      #0xF0,r0"               "\n"
1196          "      ldc     r0,sr"                  "\n"
1197          "      mov.<bwl>       %1,r0"          "\n"
1198          "      mov     r0,%0"                  "\n"
1199          "      <fetchop_name>  %2,r0"          "\n"
1200          "      mov.<bwl>       r0,%1"          "\n"
1201          "      ldc     %3,sr";
1203   "&& can_create_pseudo_p () && optimize
1204    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1205   [(const_int 0)]
1207   emit_insn (gen_atomic_<fetchop_name>_fetch<mode>_soft_imask (
1208                         gen_reg_rtx (<MODE>mode), operands[1], operands[2]));
1210   [(set_attr "length" "18")])
1212 ;; Combine pattern for xor (val, -1) / nand (val, -1).
1213 (define_insn_and_split "atomic_fetch_not<mode>_soft_imask"
1214   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1215         (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd"))
1216    (set (match_dup 1)
1217         (unspec:QIHISI [(not:QIHISI (match_dup 1))] UNSPEC_ATOMIC))
1218    (clobber (reg:SI R0_REG))
1219    (clobber (match_scratch:QIHISI 2 "=&r"))]
1220   "TARGET_ATOMIC_SOFT_IMASK"
1222   return "\r    stc     sr,r0"                  "\n"
1223          "      mov     r0,%2"                  "\n"
1224          "      or      #0xF0,r0"               "\n"
1225          "      ldc     r0,sr"                  "\n"
1226          "      mov.<bwl>       %1,r0"          "\n"
1227          "      mov     r0,%0"                  "\n"
1228          "      not     r0,r0"                  "\n"
1229          "      mov.<bwl>       r0,%1"          "\n"
1230          "      ldc     %2,sr";
1232   "&& can_create_pseudo_p () && optimize
1233    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1234   [(const_int 0)]
1236   emit_insn (gen_atomic_not_fetch<mode>_soft_imask (gen_reg_rtx (<MODE>mode),
1237                                                     operands[1]));
1239   [(set_attr "length" "18")])
1241 (define_expand "atomic_fetch_nand<mode>"
1242   [(set (match_operand:QIHISI 0 "arith_reg_dest")
1243         (match_operand:QIHISI 1 "atomic_mem_operand_1"))
1244    (set (match_dup 1)
1245         (unspec:QIHISI
1246           [(not:QIHISI (and:QIHISI (match_dup 1)
1247                        (match_operand:QIHISI 2 "atomic_logical_operand_1")))]
1248           UNSPEC_ATOMIC))
1249    (match_operand:SI 3 "const_int_operand")]
1250   "TARGET_ATOMIC_ANY"
1252   rtx mem = operands[1];
1253   rtx atomic_insn;
1255   if (TARGET_ATOMIC_HARD_LLCS
1256       || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
1257     atomic_insn = gen_atomic_fetch_nand<mode>_hard (operands[0], mem,
1258                                                     operands[2]);
1259   else if (TARGET_ATOMIC_SOFT_GUSA)
1260     atomic_insn = gen_atomic_fetch_nand<mode>_soft_gusa (operands[0], mem,
1261                                                          operands[2]);
1262   else if (TARGET_ATOMIC_SOFT_TCB)
1263     atomic_insn = gen_atomic_fetch_nand<mode>_soft_tcb (operands[0], mem,
1264                       operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
1265   else if (TARGET_ATOMIC_SOFT_IMASK)
1266     atomic_insn = gen_atomic_fetch_nand<mode>_soft_imask (operands[0], mem,
1267                                                           operands[2]);
1268   else
1269     FAIL;
1271   emit_insn (atomic_insn);
1273   if (<MODE>mode == QImode)
1274     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
1275                                      operands[0]));
1276   else if (<MODE>mode == HImode)
1277     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
1278                                      operands[0]));
1279   DONE;
1282 (define_insn_and_split "atomic_fetch_nandsi_hard"
1283   [(set (match_operand:SI 0 "arith_reg_dest" "=&r")
1284         (match_operand:SI 1 "atomic_mem_operand_1" "=Sra"))
1285    (set (match_dup 1)
1286         (unspec:SI
1287           [(not:SI (and:SI (match_dup 1)
1288                    (match_operand:SI 2 "logical_operand" "rK08")))]
1289           UNSPEC_ATOMIC))
1290    (set (reg:SI T_REG) (const_int 1))
1291    (clobber (reg:SI R0_REG))]
1292   "TARGET_ATOMIC_HARD_LLCS
1293    || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1295   return "\r0:  movli.l %1,r0"          "\n"
1296          "      mov     r0,%0"          "\n"
1297          "      and     %2,r0"          "\n"
1298          "      not     r0,r0"          "\n"
1299          "      movco.l r0,%1"          "\n"
1300          "      bf      0b";
1302   "&& can_create_pseudo_p () && optimize
1303    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1304   [(const_int 0)]
1306   emit_insn (gen_atomic_nand_fetchsi_hard (gen_reg_rtx (SImode), operands[1],
1307                                            operands[2]));
1309   [(set_attr "length" "12")])
1311 ;; The QIHImode llcs patterns modify the address register of the memory
1312 ;; operand.  In order to express that, we have to open code the memory
1313 ;; operand.  Initially the insn is expanded like every other atomic insn
1314 ;; using the memory operand.  In split1 the insn is converted and the
1315 ;; memory operand's address register is exposed.
1316 (define_insn_and_split "atomic_fetch_nand<mode>_hard"
1317   [(set (match_operand:QIHI 0 "arith_reg_dest")
1318         (match_operand:QIHI 1 "atomic_mem_operand_1"))
1319    (set (match_dup 1)
1320         (unspec:QIHI
1321           [(not:QIHI (and:QIHI (match_dup 1)
1322                      (match_operand:QIHI 2 "logical_operand" "rK08")))]
1323           UNSPEC_ATOMIC))
1324    (set (reg:SI T_REG) (const_int 1))
1325    (clobber (reg:SI R0_REG))]
1326   "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
1327   "#"
1328   "&& 1"
1329   [(const_int 0)]
1331   if (optimize
1332       && sh_reg_dead_or_unused_after_insn (curr_insn, REGNO (operands[0])))
1333     emit_insn (gen_atomic_nand<mode>_hard (operands[1], operands[2]));
1334   else
1335     {
1336       rtx i = gen_atomic_fetch_nand<mode>_hard_1 (
1337                         operands[0], XEXP (operands[1], 0), operands[2]);
1339       /* Replace the new mems in the new insn with the old mem to preserve
1340          aliasing info.  */
1341       XEXP (XVECEXP (i, 0, 0), 1) = operands[1];
1342       XEXP (XVECEXP (i, 0, 1), 0) = operands[1];
1343       XEXP (XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 1), 1), 0, 0), 0),
1344             0) = operands[1];
1345       emit_insn (i);
1346     }
1349 (define_insn "atomic_fetch_nand<mode>_hard_1"
1350   [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1351         (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")))
1352    (set (mem:QIHI (match_dup 1))
1353         (unspec:QIHI
1354           [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1))
1355                      (match_operand:QIHI 2 "logical_operand" "rK08")))]
1356           UNSPEC_ATOMIC))
1357    (set (reg:SI T_REG) (const_int 1))
1358    (clobber (reg:SI R0_REG))
1359    (clobber (match_scratch:SI 3 "=&r"))
1360    (clobber (match_scratch:SI 4 "=1"))]
1361   "TARGET_ATOMIC_HARD_LLCS"
1363   return "\r    mov     #-4,%3"                 "\n"
1364          "      and     %1,%3"                  "\n"
1365          "      xor     %3,%1"                  "\n"
1366          "      add     r15,%1"                 "\n"
1367          "      add     #-4,%1"                 "\n"
1368          "0:    movli.l @%3,r0"                 "\n"
1369          "      mov.l   r0,@-r15"               "\n"
1370          "      mov.<bw>        @%1,r0"         "\n"
1371          "      mov     r0,%0"                  "\n"
1372          "      and     %2,r0"                  "\n"
1373          "      not     r0,r0"                  "\n"
1374          "      mov.<bw>        r0,@%1"         "\n"
1375          "      mov.l   @r15+,r0"               "\n"
1376          "      movco.l r0,@%3"                 "\n"
1377          "      bf      0b";
1379   [(set_attr "length" "30")])
1381 ;; The QIHImode llcs patterns modify the address register of the memory
1382 ;; operand.  In order to express that, we have to open code the memory
1383 ;; operand.  Initially the insn is expanded like every other atomic insn
1384 ;; using the memory operand.  In split1 the insn is converted and the
1385 ;; memory operand's address register is exposed.
1386 (define_insn_and_split "atomic_nand<mode>_hard"
1387   [(set (match_operand:QIHI 0 "atomic_mem_operand_1")
1388         (unspec:QIHI
1389           [(not:QIHI (and:QIHI (match_dup 0)
1390                                (match_operand:QIHI 1 "logical_operand")))]
1391           UNSPEC_ATOMIC))
1392    (set (reg:SI T_REG) (const_int 1))
1393    (clobber (reg:SI R0_REG))]
1394   "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
1395   "#"
1396   "&& 1"
1397   [(const_int 0)]
1399   rtx i = gen_atomic_nand<mode>_hard_1 (XEXP (operands[0], 0), operands[1]);
1401   /* Replace the new mems in the new insn with the old mem to preserve
1402      aliasing info.  */
1403   XEXP (XVECEXP (i, 0, 0), 0) = operands[0];
1404   XEXP (XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 0), 1), 0, 0), 0), 0) = operands[0];
1405   emit_insn (i);
1408 (define_insn "atomic_nand<mode>_hard_1"
1409   [(set (mem:QIHI (match_operand:SI 0 "arith_reg_operand" "r"))
1410         (unspec:QIHI
1411           [(not:QIHI (and:QIHI (mem:QIHI (match_dup 0))
1412                      (match_operand:QIHI 1 "logical_operand" "rK08")))]
1413           UNSPEC_ATOMIC))
1414    (set (reg:SI T_REG) (const_int 1))
1415    (clobber (reg:SI R0_REG))
1416    (clobber (match_scratch:SI 2 "=&r"))
1417    (clobber (match_scratch:SI 3 "=0"))]
1418   "TARGET_ATOMIC_HARD_LLCS"
1420   return "\r    mov     #-4,%2"                 "\n"
1421          "      and     %0,%2"                  "\n"
1422          "      xor     %2,%0"                  "\n"
1423          "      add     r15,%0"                 "\n"
1424          "      add     #-4,%0"                 "\n"
1425          "0:    movli.l @%2,r0"                 "\n"
1426          "      mov.l   r0,@-r15"               "\n"
1427          "      mov.<bw>        @%0,r0"         "\n"
1428          "      and     %1,r0"                  "\n"
1429          "      not     r0,r0"                  "\n"
1430          "      mov.<bw>        r0,@%0"         "\n"
1431          "      mov.l   @r15+,r0"               "\n"
1432          "      movco.l r0,@%2"                 "\n"
1433          "      bf      0b";
1435   [(set_attr "length" "28")])
1437 (define_insn_and_split "atomic_fetch_nand<mode>_soft_gusa"
1438   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1439         (match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd"))
1440    (set (match_dup 1)
1441         (unspec:QIHISI
1442           [(not:QIHISI
1443              (and:QIHISI (match_dup 1)
1444                          (match_operand:QIHISI 2 "arith_reg_operand" "u")))]
1445           UNSPEC_ATOMIC))
1446    (clobber (match_scratch:QIHISI 3 "=&u"))
1447    (clobber (reg:SI R0_REG))
1448    (clobber (reg:SI R1_REG))]
1449   "TARGET_ATOMIC_SOFT_GUSA"
1451   return "\r    mova    1f,r0"                  "\n"
1452          "      mov     r15,r1"                 "\n"
1453          "      .align 2"                       "\n"
1454          "      mov     #(0f-1f),r15"           "\n"
1455          "0:    mov.<bwl>       %1,%0"          "\n"
1456          "      mov     %2,%3"                  "\n"
1457          "      and     %0,%3"                  "\n"
1458          "      not     %3,%3"                  "\n"
1459          "      mov.<bwl>       %3,%1"          "\n"
1460          "1:    mov     r1,r15";
1462   "&& can_create_pseudo_p () && optimize
1463    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1464   [(const_int 0)]
1466   emit_insn (gen_atomic_nand_fetch<mode>_soft_gusa (gen_reg_rtx (<MODE>mode),
1467                                                     operands[1], operands[2]));
1469   [(set_attr "length" "20")])
1471 (define_insn_and_split "atomic_fetch_nand<mode>_soft_tcb"
1472   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1473         (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd"))
1474    (set (match_dup 1)
1475         (unspec:QIHISI
1476           [(not:QIHISI
1477              (and:QIHISI (match_dup 1)
1478                          (match_operand:QIHISI 2 "logical_operand" "rK08")))]
1479           UNSPEC_ATOMIC))
1480    (use (match_operand:SI 3 "gbr_displacement"))
1481    (clobber (reg:SI R0_REG))
1482    (clobber (reg:SI R1_REG))]
1483   "TARGET_ATOMIC_SOFT_TCB"
1485   return "\r    mova    1f,r0"                  "\n"
1486          "      mov     #(0f-1f),r1"            "\n"
1487          "      .align 2"                       "\n"
1488          "      mov.l   r0,@(%O3,gbr)"          "\n"
1489          "0:    mov.<bwl>       %1,r0"          "\n"
1490          "      mov     r0,%0"                  "\n"
1491          "      and     %2,r0"                  "\n"
1492          "      not     r0,r0"                  "\n"
1493          "      mov.<bwl>       r0,%1"          "\n"
1494          "1:    mov     #0,r0"                  "\n"
1495          "      mov.l   r0,@(%O3,gbr)";
1497   "&& can_create_pseudo_p () && optimize
1498    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1499   [(const_int 0)]
1501   emit_insn (gen_atomic_nand<mode>_soft_tcb (operands[1], operands[2],
1502                                              operands[3]));
1504   [(set_attr "length" "22")])
1506 (define_insn "atomic_nand<mode>_soft_tcb"
1507   [(set (match_operand:QIHISI 0 "atomic_mem_operand_1" "=SraSdd")
1508         (unspec:QIHISI
1509           [(not:QIHISI
1510              (and:QIHISI (match_dup 0)
1511                          (match_operand:QIHISI 1 "logical_operand" "rK08")))]
1512           UNSPEC_ATOMIC))
1513    (use (match_operand:SI 2 "gbr_displacement"))
1514    (clobber (reg:SI R0_REG))
1515    (clobber (reg:SI R1_REG))]
1516   "TARGET_ATOMIC_SOFT_TCB"
1518   return "\r    mova    1f,r0"                  "\n"
1519          "      .align 2"                       "\n"
1520          "      mov     #(0f-1f),r1"            "\n"
1521          "      mov.l   r0,@(%O2,gbr)"          "\n"
1522          "0:    mov.<bwl>       %0,r0"          "\n"
1523          "      and     %1,r0"                  "\n"
1524          "      not     r0,r0"                  "\n"
1525          "      mov.<bwl>       r0,%0"          "\n"
1526          "1:    mov     #0,r0"                  "\n"
1527          "      mov.l   r0,@(%O2,gbr)";
1529   [(set_attr "length" "20")])
1531 (define_insn_and_split "atomic_fetch_nand<mode>_soft_imask"
1532   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1533         (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd"))
1534    (set (match_dup 1)
1535         (unspec:QIHISI
1536           [(not:QIHISI
1537              (and:QIHISI (match_dup 1)
1538                          (match_operand:QIHISI 2 "logical_operand" "rK08")))]
1539           UNSPEC_ATOMIC))
1540    (clobber (reg:SI R0_REG))
1541    (clobber (match_scratch:SI 3 "=&r"))]
1542   "TARGET_ATOMIC_SOFT_IMASK"
1544   return "\r    stc     sr,r0"                  "\n"
1545          "      mov     r0,%3"                  "\n"
1546          "      or      #0xF0,r0"               "\n"
1547          "      ldc     r0,sr"                  "\n"
1548          "      mov.<bwl>       %1,r0"          "\n"
1549          "      mov     r0,%0"                  "\n"
1550          "      and     %2,r0"                  "\n"
1551          "      not     r0,r0"                  "\n"
1552          "      mov.<bwl>       r0,%1"          "\n"
1553          "      ldc     %3,sr";
1555   "&& can_create_pseudo_p () && optimize
1556    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1557   [(const_int 0)]
1559   emit_insn (gen_atomic_nand_fetch<mode>_soft_imask (gen_reg_rtx (<MODE>mode),
1560                                                      operands[1], operands[2]));
1562   [(set_attr "length" "20")])
1564 ;;------------------------------------------------------------------------------
1565 ;; read - add|sub|or|and|xor|nand - write - return new value
1567 (define_expand "atomic_<fetchop_name>_fetch<mode>"
1568   [(set (match_operand:QIHISI 0 "arith_reg_dest")
1569         (FETCHOP:QIHISI
1570           (match_operand:QIHISI 1 "atomic_mem_operand_1")
1571           (match_operand:QIHISI 2 "<fetchop_predicate_1>")))
1572    (set (match_dup 1)
1573         (unspec:QIHISI
1574           [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))]
1575           UNSPEC_ATOMIC))
1576    (match_operand:SI 3 "const_int_operand" "")]
1577   "TARGET_ATOMIC_ANY"
1579   rtx mem = operands[1];
1580   rtx atomic_insn;
1582   if (TARGET_ATOMIC_HARD_LLCS
1583       || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
1584     atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_hard (operands[0], mem,
1585                                                               operands[2]);
1586   else if (TARGET_ATOMIC_SOFT_GUSA)
1587     atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_gusa (operands[0],
1588                       mem, operands[2]);
1589   else if (TARGET_ATOMIC_SOFT_TCB)
1590     atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_tcb (operands[0],
1591                       mem, operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
1592   else if (TARGET_ATOMIC_SOFT_IMASK)
1593     atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_imask (operands[0],
1594                       mem, operands[2]);
1595   else
1596     FAIL;
1598   emit_insn (atomic_insn);
1600   if (<MODE>mode == QImode)
1601     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
1602                                      operands[0]));
1603   else if (<MODE>mode == HImode)
1604     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
1605                                      operands[0]));
1606   DONE;
1609 (define_insn "atomic_<fetchop_name>_fetchsi_hard"
1610   [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
1611         (FETCHOP:SI
1612           (match_operand:SI 1 "atomic_mem_operand_1" "=Sra")
1613           (match_operand:SI 2 "<fetchop_predicate_1>"
1614                               "<fetchop_constraint_1_llcs>")))
1615    (set (match_dup 1)
1616         (unspec:SI
1617           [(FETCHOP:SI (match_dup 1) (match_dup 2))]
1618           UNSPEC_ATOMIC))
1619    (set (reg:SI T_REG) (const_int 1))]
1620   "TARGET_ATOMIC_HARD_LLCS
1621    || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1623   return "\r0:  movli.l %1,%0"          "\n"
1624          "      <fetchop_name>  %2,%0"  "\n"
1625          "      movco.l %0,%1"          "\n"
1626          "      bf      0b";
1628   [(set_attr "length" "8")])
1630 ;; Combine pattern for xor (val, -1) / nand (val, -1).
1631 (define_insn "atomic_not_fetchsi_hard"
1632   [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
1633         (not:SI (match_operand:SI 1 "atomic_mem_operand_1" "=Sra")))
1634    (set (match_dup 1)
1635         (unspec:SI [(not:SI (match_dup 1))] UNSPEC_ATOMIC))
1636    (set (reg:SI T_REG) (const_int 1))]
1637   "TARGET_ATOMIC_HARD_LLCS
1638    || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1640   return "\r0:  movli.l %1,%0"          "\n"
1641          "      not     %0,%0"          "\n"
1642          "      movco.l %0,%1"          "\n"
1643          "      bf      0b";
1645   [(set_attr "length" "8")])
1647 ;; The QIHImode llcs patterns modify the address register of the memory
1648 ;; operand.  In order to express that, we have to open code the memory
1649 ;; operand.  Initially the insn is expanded like every other atomic insn
1650 ;; using the memory operand.  In split1 the insn is converted and the
1651 ;; memory operand's address register is exposed.
1652 (define_insn_and_split "atomic_<fetchop_name>_fetch<mode>_hard"
1653   [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1654         (FETCHOP:QIHI (match_operand:QIHI 1 "atomic_mem_operand_1")
1655                       (match_operand:QIHI 2 "<fetchop_predicate_1>")))
1656    (set (match_dup 1) (unspec:QIHI [(FETCHOP:QIHI (match_dup 1) (match_dup 2))]
1657                                    UNSPEC_ATOMIC))
1658    (set (reg:SI T_REG) (const_int 1))
1659    (clobber (reg:SI R0_REG))]
1660   "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
1661   "#"
1662   "&& 1"
1663   [(const_int 0)]
1665   if (optimize
1666       && sh_reg_dead_or_unused_after_insn (curr_insn, REGNO (operands[0])))
1667     emit_insn (gen_atomic_<fetchop_name><mode>_hard (operands[1], operands[2]));
1668   else
1669     {
1670       rtx i = gen_atomic_<fetchop_name>_fetch<mode>_hard_1 (
1671                         operands[0], XEXP (operands[1], 0), operands[2]);
1673       /* Replace the new mems in the new insn with the old mem to preserve
1674          aliasing info.  */
1675       XEXP (XEXP (XVECEXP (i, 0, 0), 1), 0) = operands[1];
1676       XEXP (XVECEXP (i, 0, 1), 0) = operands[1];
1677       XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 1), 1), 0, 0), 0) = operands[1];
1678       emit_insn (i);
1679     }
1682 (define_insn "atomic_<fetchop_name>_fetch<mode>_hard_1"
1683   [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1684         (FETCHOP:QIHI
1685           (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
1686           (match_operand:QIHI 2 "<fetchop_predicate_1>"
1687                                 "<fetchop_constraint_1_llcs>")))
1688    (set (mem:QIHI (match_dup 1))
1689         (unspec:QIHI
1690           [(FETCHOP:QIHI (mem:QIHI (match_dup 1)) (match_dup 2))]
1691           UNSPEC_ATOMIC))
1692    (set (reg:SI T_REG) (const_int 1))
1693    (clobber (reg:SI R0_REG))
1694    (clobber (match_scratch:SI 3 "=&r"))
1695    (clobber (match_scratch:SI 4 "=1"))]
1696   "TARGET_ATOMIC_HARD_LLCS"
1698   return "\r    mov     #-4,%3"                 "\n"
1699          "      and     %1,%3"                  "\n"
1700          "      xor     %3,%1"                  "\n"
1701          "      add     r15,%1"                 "\n"
1702          "      add     #-4,%1"                 "\n"
1703          "0:    movli.l @%3,r0"                 "\n"
1704          "      mov.l   r0,@-r15"               "\n"
1705          "      mov.<bw>        @%1,r0"         "\n"
1706          "      <fetchop_name>  %2,r0"          "\n"
1707          "      mov.<bw>        r0,@%1"         "\n"
1708          "      mov     r0,%0"                  "\n"
1709          "      mov.l   @r15+,r0"               "\n"
1710          "      movco.l r0,@%3"                 "\n"
1711          "      bf      0b";
1713   [(set_attr "length" "28")])
1715 ;; Combine pattern for xor (val, -1) / nand (val, -1).
1716 (define_insn_and_split "atomic_not_fetch<mode>_hard"
1717   [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1718         (not:QIHI (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))))
1719    (set (mem:QIHI (match_dup 1))
1720         (unspec:QIHI [(not:QIHI (mem:QIHI (match_dup 1)))] UNSPEC_ATOMIC))
1721    (set (reg:SI T_REG) (const_int 1))
1722    (clobber (reg:SI R0_REG))
1723    (clobber (match_scratch:SI 2 "=&r"))
1724    (clobber (match_scratch:SI 3 "=1"))]
1725   "TARGET_ATOMIC_HARD_LLCS"
1727   return "\r    mov     #-4,%2"                 "\n"
1728          "      and     %1,%2"                  "\n"
1729          "      xor     %2,%1"                  "\n"
1730          "      add     r15,%1"                 "\n"
1731          "      add     #-4,%1"                 "\n"
1732          "0:    movli.l @%2,r0"                 "\n"
1733          "      mov.l   r0,@-r15"               "\n"
1734          "      mov.<bw>        @%1,r0"         "\n"
1735          "      not     r0,r0"                  "\n"
1736          "      mov.<bw>        r0,@%1"         "\n"
1737          "      mov     r0,%0"                  "\n"
1738          "      mov.l   @r15+,r0"               "\n"
1739          "      movco.l r0,@%2"                 "\n"
1740          "      bf      0b";
1742   "&& can_create_pseudo_p () && optimize
1743    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1744   [(const_int 0)]
1746   rtx i = gen_atomic_not<mode>_hard (operands[1]);
1748   /* Replace the new mems in the new insn with the old mem to preserve
1749      aliasing info.  */
1750   rtx m = XEXP (XEXP (XVECEXP (PATTERN (curr_insn), 0, 0), 1), 0);
1751   XEXP (XVECEXP (i, 0, 0), 0) = m;
1752   XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 0), 1), 0, 0), 0) = m;
1753   emit_insn (i);
1755   [(set_attr "length" "28")])
1757 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_gusa"
1758   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1759         (FETCHOP:QIHISI
1760           (match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd")
1761           (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1762                                   "<fetchop_constraint_1_gusa>")))
1763    (set (match_dup 1)
1764         (unspec:QIHISI
1765           [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))]
1766           UNSPEC_ATOMIC))
1767    (clobber (reg:SI R0_REG))
1768    (clobber (reg:SI R1_REG))]
1769   "TARGET_ATOMIC_SOFT_GUSA"
1771   return "\r    mova    1f,r0"                  "\n"
1772          "      mov     r15,r1"                 "\n"
1773          "      .align 2"                       "\n"
1774          "      mov     #(0f-1f),r15"           "\n"
1775          "0:    mov.<bwl>       %1,%0"          "\n"
1776          "      <fetchop_name>  %2,%0"          "\n"
1777          "      mov.<bwl>       %0,%1"          "\n"
1778          "1:    mov     r1,r15";
1780   [(set_attr "length" "16")])
1782 ;; Combine pattern for xor (val, -1) / nand (val, -1).
1783 (define_insn "atomic_not_fetch<mode>_soft_gusa"
1784   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
1785         (not:QIHISI (match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd")))
1786    (set (match_dup 1)
1787         (unspec:QIHISI [(not:QIHISI (match_dup 1))] UNSPEC_ATOMIC))
1788    (clobber (reg:SI R0_REG))
1789    (clobber (reg:SI R1_REG))]
1790   "TARGET_ATOMIC_SOFT_GUSA"
1792   return "\r    mova    1f,r0"                  "\n"
1793          "      mov     r15,r1"                 "\n"
1794          "      .align 2"                       "\n"
1795          "      mov     #(0f-1f),r15"           "\n"
1796          "0:    mov.<bwl>       %1,%0"          "\n"
1797          "      not     %0,%0"                  "\n"
1798          "      mov.<bwl>       %0,%1"          "\n"
1799          "1:    mov     r1,r15";
1801   [(set_attr "length" "16")])
1803 (define_insn_and_split "atomic_<fetchop_name>_fetch<mode>_soft_tcb"
1804   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1805         (FETCHOP:QIHISI
1806           (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")
1807           (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1808                                   "<fetchop_constraint_1_tcb>")))
1809    (set (match_dup 1)
1810         (unspec:QIHISI
1811           [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))]
1812           UNSPEC_ATOMIC))
1813    (clobber (reg:SI R0_REG))
1814    (clobber (reg:SI R1_REG))
1815    (use (match_operand:SI 3 "gbr_displacement"))]
1816   "TARGET_ATOMIC_SOFT_TCB"
1818   return "\r    mova    1f,r0"                  "\n"
1819          "      mov     #(0f-1f),r1"            "\n"
1820          "      .align 2"                       "\n"
1821          "      mov.l   r0,@(%O3,gbr)"          "\n"
1822          "0:    mov.<bwl>       %1,r0"          "\n"
1823          "      <fetchop_name>  %2,r0"          "\n"
1824          "      mov.<bwl>       r0,%1"          "\n"
1825          "1:    mov     r0,%0"                  "\n"
1826          "      mov     #0,r0"                  "\n"
1827          "      mov.l   r0,@(%O3,gbr)";
1829   "&& can_create_pseudo_p () && optimize
1830    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1831   [(const_int 0)]
1833   emit_insn (gen_atomic_<fetchop_name><mode>_soft_tcb (
1834                                 operands[1], operands[2], operands[3]));
1836   [(set_attr "length" "20")])
1838 ;; Combine pattern for xor (val, -1) / nand (val, -1).
1839 (define_insn_and_split "atomic_not_fetch<mode>_soft_tcb"
1840   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
1841         (not:QIHISI (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")))
1842    (set (match_dup 1)
1843         (unspec:QIHISI [(not:QIHISI (match_dup 1))] UNSPEC_ATOMIC))
1844    (clobber (reg:SI R0_REG))
1845    (clobber (reg:SI R1_REG))
1846    (use (match_operand:SI 2 "gbr_displacement"))]
1847   "TARGET_ATOMIC_SOFT_TCB"
1849   return "\r    mova    1f,r0"                  "\n"
1850          "      mov     #(0f-1f),r1"            "\n"
1851          "      .align 2"                       "\n"
1852          "      mov.l   r0,@(%O2,gbr)"          "\n"
1853          "0:    mov.<bwl>       %1,r0"          "\n"
1854          "      not     r0,r0"                  "\n"
1855          "      mov.<bwl>       r0,%1"          "\n"
1856          "1:    mov     r0,%0"                  "\n"
1857          "      mov     #0,r0"                  "\n"
1858          "      mov.l   r0,@(%O2,gbr)";
1860   "&& can_create_pseudo_p () && optimize
1861    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
1862   [(const_int 0)]
1864   emit_insn (gen_atomic_not<mode>_soft_tcb (operands[1], operands[2]));
1866   [(set_attr "length" "20")])
1868 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_imask"
1869   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
1870         (FETCHOP:QIHISI
1871           (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")
1872           (match_operand:QIHISI 2 "<fetchop_predicate_1>"
1873                                   "<fetchop_constraint_1_imask>")))
1874    (set (match_dup 1)
1875         (unspec:QIHISI
1876           [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))]
1877           UNSPEC_ATOMIC))
1878    (clobber (match_scratch:SI 3 "=&r"))]
1879   "TARGET_ATOMIC_SOFT_IMASK"
1881   return "\r    stc     sr,%0"                  "\n"
1882          "      mov     %0,%3"                  "\n"
1883          "      or      #0xF0,%0"               "\n"
1884          "      ldc     %0,sr"                  "\n"
1885          "      mov.<bwl>       %1,%0"          "\n"
1886          "      <fetchop_name>  %2,%0"          "\n"
1887          "      mov.<bwl>       %0,%1"          "\n"
1888          "      ldc     %3,sr";
1890   [(set_attr "length" "16")])
1892 ;; Combine pattern for xor (val, -1) / nand (val, -1).
1893 (define_insn "atomic_not_fetch<mode>_soft_imask"
1894   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
1895         (not:QIHISI (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")))
1896    (set (match_dup 1)
1897         (unspec:QIHISI [(not:QIHISI (match_dup 1))] UNSPEC_ATOMIC))
1898    (clobber (match_scratch:SI 2 "=&r"))]
1899   "TARGET_ATOMIC_SOFT_IMASK"
1901   return "\r    stc     sr,%0"                  "\n"
1902          "      mov     %0,%2"                  "\n"
1903          "      or      #0xF0,%0"               "\n"
1904          "      ldc     %0,sr"                  "\n"
1905          "      mov.<bwl>       %1,%0"          "\n"
1906          "      not     %0,%0"                  "\n"
1907          "      mov.<bwl>       %0,%1"          "\n"
1908          "      ldc     %2,sr";
1910   [(set_attr "length" "16")])
1912 (define_expand "atomic_nand_fetch<mode>"
1913   [(set (match_operand:QIHISI 0 "arith_reg_dest")
1914         (not:QIHISI (and:QIHISI
1915           (match_operand:QIHISI 1 "atomic_mem_operand_1")
1916           (match_operand:QIHISI 2 "atomic_logical_operand_1"))))
1917    (set (match_dup 1)
1918         (unspec:QIHISI
1919           [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))]
1920           UNSPEC_ATOMIC))
1921    (match_operand:SI 3 "const_int_operand")]
1922   "TARGET_ATOMIC_ANY"
1924   rtx mem = operands[1];
1925   rtx atomic_insn;
1927   if (TARGET_ATOMIC_HARD_LLCS
1928       || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT))
1929     atomic_insn = gen_atomic_nand_fetch<mode>_hard (operands[0], mem,
1930                                                     operands[2]);
1931   else if (TARGET_ATOMIC_SOFT_GUSA)
1932     atomic_insn = gen_atomic_nand_fetch<mode>_soft_gusa (operands[0], mem,
1933                                                          operands[2]);
1934   else if (TARGET_ATOMIC_SOFT_TCB)
1935     atomic_insn = gen_atomic_nand_fetch<mode>_soft_tcb (operands[0], mem,
1936                       operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX);
1937   else if (TARGET_ATOMIC_SOFT_IMASK)
1938     atomic_insn = gen_atomic_nand_fetch<mode>_soft_imask (operands[0], mem,
1939                                                           operands[2]);
1940   else
1941     FAIL;
1943   emit_insn (atomic_insn);
1945   if (<MODE>mode == QImode)
1946     emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
1947                                      operands[0]));
1948   else if (<MODE>mode == HImode)
1949     emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
1950                                      operands[0]));
1951   DONE;
1954 (define_insn "atomic_nand_fetchsi_hard"
1955   [(set (match_operand:SI 0 "arith_reg_dest" "=&z")
1956         (not:SI (and:SI (match_operand:SI 1 "atomic_mem_operand_1" "=Sra")
1957                         (match_operand:SI 2 "logical_operand" "rK08"))))
1958    (set (match_dup 1)
1959         (unspec:SI
1960           [(not:SI (and:SI (match_dup 1) (match_dup 2)))]
1961           UNSPEC_ATOMIC))
1962    (set (reg:SI T_REG) (const_int 1))]
1963   "TARGET_ATOMIC_HARD_LLCS
1964    || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)"
1966   return "\r0:  movli.l %1,%0"          "\n"
1967          "      and     %2,%0"          "\n"
1968          "      not     %0,%0"          "\n"
1969          "      movco.l %0,%1"          "\n"
1970          "      bf      0b";
1972   [(set_attr "length" "10")])
1974 ;; The QIHImode llcs patterns modify the address register of the memory
1975 ;; operand.  In order to express that, we have to open code the memory
1976 ;; operand.  Initially the insn is expanded like every other atomic insn
1977 ;; using the memory operand.  In split1 the insn is converted and the
1978 ;; memory operand's address register is exposed.
1979 (define_insn_and_split "atomic_nand_fetch<mode>_hard"
1980   [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
1981         (not:QIHI (and:QIHI (match_operand:QIHI 1 "atomic_mem_operand_1")
1982                             (match_operand:QIHI 2 "logical_operand"))))
1983    (set (match_dup 1)
1984         (unspec:QIHI [(not:QIHI (and:QIHI (match_dup 1) (match_dup 2)))]
1985                      UNSPEC_ATOMIC))
1986    (set (reg:SI T_REG) (const_int 1))
1987    (clobber (reg:SI R0_REG))]
1988   "TARGET_ATOMIC_HARD_LLCS && can_create_pseudo_p ()"
1989   "#"
1990   "&& 1"
1991   [(const_int 0)]
1993   if (optimize
1994       && sh_reg_dead_or_unused_after_insn (curr_insn, REGNO (operands[0])))
1995     emit_insn (gen_atomic_nand<mode>_hard (operands[1], operands[2]));
1996   else
1997     {
1998       rtx i = gen_atomic_nand_fetch<mode>_hard_1 (
1999                         operands[0], XEXP (operands[1], 0), operands[2]);
2000       
2001       /* Replace the new mems in the new insn with the old mem to preserve
2002          aliasing info.  */
2003       XEXP (XEXP (XEXP (XVECEXP (i, 0, 0), 1), 0), 0) = operands[1];
2004       XEXP (XVECEXP (i, 0, 1), 0) = operands[1];
2005       XEXP (XEXP (XVECEXP (XEXP (XVECEXP (i, 0, 1), 1), 0, 0), 0),
2006             0) = operands[1];
2007       emit_insn (i);
2008     }
2011 (define_insn "atomic_nand_fetch<mode>_hard_1"
2012   [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r")
2013         (not:QIHI
2014           (and:QIHI (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))
2015                     (match_operand:QIHI 2 "logical_operand" "rK08"))))
2016    (set (mem:QIHI (match_dup 1))
2017         (unspec:QIHI
2018           [(not:QIHI (and:QIHI (mem:QIHI (match_dup 1)) (match_dup 2)))]
2019           UNSPEC_ATOMIC))
2020    (set (reg:SI T_REG) (const_int 1))
2021    (clobber (reg:SI R0_REG))
2022    (clobber (match_scratch:SI 3 "=&r"))
2023    (clobber (match_scratch:SI 4 "=1"))]
2024   "TARGET_ATOMIC_HARD_LLCS"
2026   return "\r    mov     #-4,%3"                 "\n"
2027          "      and     %1,%3"                  "\n"
2028          "      xor     %3,%1"                  "\n"
2029          "      add     r15,%1"                 "\n"
2030          "      add     #-4,%1"                 "\n"
2031          "0:    movli.l @%3,r0"                 "\n"
2032          "      mov.l   r0,@-r15"               "\n"
2033          "      mov.<bw>        @%1,r0"         "\n"
2034          "      and     %2,r0"                  "\n"
2035          "      not     r0,%0"                  "\n"
2036          "      mov.<bw>        %0,@%1"         "\n"
2037          "      mov.l   @r15+,r0"               "\n"
2038          "      movco.l r0,@%3"                 "\n"
2039          "      bf      0b";
2041   [(set_attr "length" "28")])
2043 (define_insn "atomic_nand_fetch<mode>_soft_gusa"
2044   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u")
2045         (not:QIHISI (and:QIHISI
2046           (match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd")
2047           (match_operand:QIHISI 2 "arith_reg_operand" "u"))))
2048    (set (match_dup 1)
2049         (unspec:QIHISI
2050           [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))]
2051           UNSPEC_ATOMIC))
2052    (clobber (reg:SI R0_REG))
2053    (clobber (reg:SI R1_REG))]
2054   "TARGET_ATOMIC_SOFT_GUSA"
2056   return "\r    mova    1f,r0"                  "\n"
2057          "      .align 2"                       "\n"
2058          "      mov     r15,r1"                 "\n"
2059          "      mov     #(0f-1f),r15"           "\n"
2060          "0:    mov.<bwl>       %1,%0"          "\n"
2061          "      and     %2,%0"                  "\n"
2062          "      not     %0,%0"                  "\n"
2063          "      mov.<bwl>       %0,%1"          "\n"
2064          "1:    mov     r1,r15";
2066   [(set_attr "length" "18")])
2068 (define_insn_and_split "atomic_nand_fetch<mode>_soft_tcb"
2069   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r")
2070         (not:QIHISI (and:QIHISI
2071           (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")
2072           (match_operand:QIHISI 2 "logical_operand" "rK08"))))
2073    (set (match_dup 1)
2074         (unspec:QIHISI
2075           [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))]
2076           UNSPEC_ATOMIC))
2077    (clobber (reg:SI R0_REG))
2078    (clobber (reg:SI R1_REG))
2079    (use (match_operand:SI 3 "gbr_displacement"))]
2080   "TARGET_ATOMIC_SOFT_TCB"
2082   return "\r    mova    1f,r0"                  "\n"
2083          "      mov     #(0f-1f),r1"            "\n"
2084          "      .align 2"                       "\n"
2085          "      mov.l   r0,@(%O3,gbr)"          "\n"
2086          "0:    mov.<bwl>       %1,r0"          "\n"
2087          "      and     %2,r0"                  "\n"
2088          "      not     r0,r0"                  "\n"
2089          "      mov     r0,%0"                  "\n"
2090          "      mov.<bwl>       r0,%1"          "\n"
2091          "1:    mov     #0,r0"                  "\n"
2092          "      mov.l   r0,@(%O3,gbr)";
2094   "&& can_create_pseudo_p () && optimize
2095    && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))"
2096   [(const_int 0)]
2098   emit_insn (gen_atomic_nand<mode>_soft_tcb (operands[1], operands[2],
2099                                              operands[3]));
2101   [(set_attr "length" "22")])
2103 (define_insn "atomic_nand_fetch<mode>_soft_imask"
2104   [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z")
2105         (not:QIHISI (and:QIHISI
2106           (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")
2107           (match_operand:QIHISI 2 "logical_operand" "rK08"))))
2108    (set (match_dup 1)
2109         (unspec:QIHISI
2110           [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))]
2111           UNSPEC_ATOMIC))
2112    (clobber (match_scratch:SI 3 "=&r"))]
2113   "TARGET_ATOMIC_SOFT_IMASK"
2115   return "\r    stc     sr,%0"                  "\n"
2116          "      mov     %0,%3"                  "\n"
2117          "      or      #0xF0,%0"               "\n"
2118          "      ldc     %0,sr"                  "\n"
2119          "      mov.<bwl>       %1,%0"          "\n"
2120          "      and     %2,%0"                  "\n"
2121          "      not     %0,%0"                  "\n"
2122          "      mov.<bwl>       %0,%1"          "\n"
2123          "      ldc     %3,sr";
2125   [(set_attr "length" "18")])
2127 ;;------------------------------------------------------------------------------
2128 ;; read - test against zero - or with 0x80 - write - return test result
2130 (define_expand "atomic_test_and_set"
2131   [(match_operand:SI 0 "register_operand" "")           ;; bool result output
2132    (match_operand:QI 1 "memory_operand" "")             ;; memory
2133    (match_operand:SI 2 "const_int_operand" "")]         ;; model
2134   "TARGET_ATOMIC_ANY || TARGET_ENABLE_TAS"
2136   rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
2138   if (TARGET_ENABLE_TAS)
2139     emit_insn (gen_tasb (addr));
2140   else
2141     {
2142       rtx val = gen_int_mode (targetm.atomic_test_and_set_trueval, QImode);
2143       val = force_reg (QImode, val);
2145       if (TARGET_ATOMIC_HARD_LLCS)
2146           emit_insn (gen_atomic_test_and_set_hard (addr, val));
2147       else if (TARGET_ATOMIC_SOFT_GUSA)
2148           emit_insn (gen_atomic_test_and_set_soft_gusa (addr, val));
2149       else if (TARGET_ATOMIC_SOFT_TCB)
2150           emit_insn (gen_atomic_test_and_set_soft_tcb (addr, val,
2151                          TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX));
2152       else if (TARGET_ATOMIC_SOFT_IMASK)
2153           emit_insn (gen_atomic_test_and_set_soft_imask (addr, val));
2154       else
2155         FAIL;
2156     }
2158   /* The result of the test op is the inverse of what we are
2159      supposed to return.  Thus invert the T bit.  The inversion will be
2160      potentially optimized away and integrated into surrounding code.  */
2161   emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ()));
2162   DONE;
2165 (define_insn "tasb"
2166   [(set (reg:SI T_REG)
2167         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
2168                (const_int 0)))
2169    (set (mem:QI (match_dup 0))
2170         (unspec:QI [(const_int 128)] UNSPEC_ATOMIC))]
2171   "TARGET_ENABLE_TAS"
2172   "tas.b        @%0"
2173   [(set_attr "insn_class" "co_group")])
2175 (define_insn "atomic_test_and_set_soft_gusa"
2176   [(set (reg:SI T_REG)
2177         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "u"))
2178                (const_int 0)))
2179    (set (mem:QI (match_dup 0))
2180         (unspec:QI [(match_operand:QI 1 "register_operand" "u")] UNSPEC_ATOMIC))
2181    (clobber (match_scratch:QI 2 "=&u"))
2182    (clobber (reg:SI R0_REG))
2183    (clobber (reg:SI R1_REG))]
2184   "TARGET_ATOMIC_SOFT_GUSA && !TARGET_ENABLE_TAS"
2186   return "\r    mova    1f,r0"          "\n"
2187          "      .align 2"               "\n"
2188          "      mov     r15,r1"         "\n"
2189          "      mov     #(0f-1f),r15"   "\n"
2190          "0:    mov.b   @%0,%2"         "\n"
2191          "      mov.b   %1,@%0"         "\n"
2192          "1:    mov     r1,r15"         "\n"
2193          "      tst     %2,%2";
2195   [(set_attr "length" "16")])
2197 (define_insn "atomic_test_and_set_soft_tcb"
2198   [(set (reg:SI T_REG)
2199         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
2200                (const_int 0)))
2201    (set (mem:QI (match_dup 0))
2202         (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
2203    (use (match_operand:SI 2 "gbr_displacement"))
2204    (clobber (match_scratch:QI 3 "=&r"))
2205    (clobber (reg:SI R0_REG))
2206    (clobber (reg:SI R1_REG))]
2207   "TARGET_ATOMIC_SOFT_TCB && !TARGET_ENABLE_TAS"
2209   return "\r    mova    1f,r0"          "\n"
2210          "      mov     #(0f-1f),r1"    "\n"
2211          "      .align 2"               "\n"
2212          "      mov.l   r0,@(%O2,gbr)"  "\n"
2213          "0:    mov.b   @%0,%3"         "\n"
2214          "      mov     #0,r0"          "\n"
2215          "      mov.b   %1,@%0"         "\n"
2216          "1:    mov.l   r0,@(%O2,gbr)"  "\n"
2217          "      tst     %3,%3";
2219   [(set_attr "length" "18")])
2221 (define_insn "atomic_test_and_set_soft_imask"
2222   [(set (reg:SI T_REG)
2223         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
2224                (const_int 0)))
2225    (set (mem:QI (match_dup 0))
2226         (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
2227    (clobber (match_scratch:SI 2 "=&r"))
2228    (clobber (reg:SI R0_REG))]
2229   "TARGET_ATOMIC_SOFT_IMASK && !TARGET_ENABLE_TAS"
2231   return "\r    stc     sr,r0"          "\n"
2232          "      mov     r0,%2"          "\n"
2233          "      or      #0xF0,r0"       "\n"
2234          "      ldc     r0,sr"          "\n"
2235          "      mov.b   @%0,r0"         "\n"
2236          "      mov.b   %1,@%0"         "\n"
2237          "      ldc     %2,sr"          "\n"
2238          "      tst     r0,r0";
2240   [(set_attr "length" "16")])
2242 (define_insn "atomic_test_and_set_hard"
2243   [(set (reg:SI T_REG)
2244         (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
2245                (const_int 0)))
2246    (set (mem:QI (match_dup 0))
2247         (unspec:QI [(match_operand:QI 1 "register_operand" "r")] UNSPEC_ATOMIC))
2248    (clobber (reg:SI R0_REG))
2249    (clobber (match_scratch:SI 2 "=&r"))
2250    (clobber (match_scratch:SI 3 "=&r"))
2251    (clobber (match_scratch:SI 4 "=0"))]
2252   "TARGET_ATOMIC_HARD_LLCS && !TARGET_ENABLE_TAS"
2254   return "\r    mov     #-4,%2"         "\n"
2255          "      and     %0,%2"          "\n"
2256          "      xor     %2,%0"          "\n"
2257          "      add     r15,%0"         "\n"
2258          "      add     #-4,%0"         "\n"
2259          "0:    movli.l @%2,r0"         "\n"
2260          "      mov.l   r0,@-r15"       "\n"
2261          "      mov.b   @%0,%3"         "\n"
2262          "      mov.b   %1,@%0"         "\n"
2263          "      mov.l   @r15+,r0"       "\n"
2264          "      movco.l r0,@%2"         "\n"
2265          "      bf      0b"             "\n"
2266          "      tst     %3,%3";
2268   [(set_attr "length" "26")])