]>
Commit | Line | Data |
---|---|---|
7768ec4c | 1 | ;; GCC machine description for SH synchronization instructions. |
a5544970 | 2 | ;; Copyright (C) 2011-2019 Free Software Foundation, Inc. |
7768ec4c KK |
3 | ;; |
4 | ;; This file is part of GCC. | |
5 | ;; | |
6 | ;; GCC is free software; you can redistribute it and/or modify | |
7 | ;; it under the terms of the GNU General Public License as published by | |
8 | ;; the Free Software Foundation; either version 3, or (at your option) | |
9 | ;; any later version. | |
10 | ;; | |
11 | ;; GCC is distributed in the hope that it will be useful, | |
12 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | ;; GNU General Public License for more details. | |
15 | ;; | |
16 | ;; You should have received a copy of the GNU General Public License | |
17 | ;; along with GCC; see the file COPYING3. If not see | |
18 | ;; <http://www.gnu.org/licenses/>. | |
f3322315 OE |
19 | ;; |
20 | ;; | |
21 | ;; Atomic integer operations for the Renesas / SuperH SH CPUs. | |
22 | ;; | |
c11394f8 | 23 | ;; On SH CPUs atomic integer operations can be done either in 'software' or |
7bd76b9c OE |
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. | |
c11394f8 | 30 | ;; |
487ebcbf | 31 | ;; tas.b atomic_test_and_set (-mtas) |
c11394f8 OE |
32 | ;; |
33 | ;; Depending on the particular hardware configuration, usage of the 'tas.b' | |
34 | ;; instruction might be undesired or even unsafe. Thus, it has to be | |
487ebcbf | 35 | ;; enabled by the user explicitly. If it is not enabled, the |
c11394f8 OE |
36 | ;; 'atomic_test_and_set' builtin is implemented either with hardware or with |
37 | ;; software atomics, depending on which is enabled. It is also possible to | |
38 | ;; enable the 'tas.b' instruction only, without enabling support for the | |
39 | ;; other atomic operations. | |
40 | ;; | |
41 | ;; | |
7bd76b9c | 42 | ;; Hardware Atomics (-matomic-model=hard-llcs; SH4A only) |
c11394f8 OE |
43 | ;; |
44 | ;; Hardware atomics implement all atomic operations using the 'movli.l' and | |
45 | ;; 'movco.l' instructions that are availble on SH4A. On multi-core hardware | |
46 | ;; configurations hardware atomics is the only safe mode. | |
47 | ;; However, it can also be safely used on single-core configurations. | |
48 | ;; Since these instructions operate on SImode memory only, QImode and HImode | |
49 | ;; have to be emulated with SImode and subreg masking, which results in | |
50 | ;; larger code. | |
51 | ;; | |
52 | ;; | |
7bd76b9c | 53 | ;; gUSA Software Atomics (-matomic-model=soft-gusa; SH3*, SH4* only) |
c11394f8 | 54 | ;; |
f3322315 OE |
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 | |
c11394f8 OE |
58 | ;; operations. This requires complementary support in the interrupt / |
59 | ;; exception handling code (e.g. kernel) and does not work safely on multi- | |
60 | ;; core configurations. | |
61 | ;; | |
f3322315 OE |
62 | ;; When an execution context is interrupted while it is an atomic |
63 | ;; sequence, the interrupted context's PC is rewound to the beginning of | |
64 | ;; the atomic sequence by the interrupt / exception handling code, before | |
65 | ;; transferring control to another execution context. This is done by | |
66 | ;; something like... | |
67 | ;; | |
68 | ;; if (interrupted_context_in_atomic_sequence | |
69 | ;; && interrupted_pc < atomic_exitpoint) | |
70 | ;; interrupted_pc = atomic_entrypoint; | |
71 | ;; | |
72 | ;; This method is also known as gUSA ("g" User Space Atomicity) and the | |
7bd76b9c OE |
73 | ;; Linux kernel for SH3/SH4 implements support for such software atomic |
74 | ;; sequences. It can also be implemented in freestanding environments. | |
f3322315 OE |
75 | ;; |
76 | ;; For this the following atomic sequence ABI is used. | |
77 | ;; | |
78 | ;; r15 >= 0: Execution context is not in an atomic sequence. | |
79 | ;; | |
80 | ;; r15 < 0: Execution context is in an atomic sequence and r15 | |
81 | ;; holds the negative byte length of the atomic sequence. | |
82 | ;; In this case the following applies: | |
83 | ;; | |
84 | ;; r0: PC of the first instruction after the atomic | |
85 | ;; write-back instruction (exit point). | |
86 | ;; The entry point PC of the atomic sequence can be | |
87 | ;; determined by doing r0 + r15. | |
88 | ;; | |
89 | ;; r1: Saved r15 stack pointer before entering the | |
90 | ;; atomic sequence. | |
91 | ;; | |
92 | ;; An example atomic add sequence would look like: | |
93 | ;; | |
94 | ;; mova .Lend,r0 ! .Lend must be 4-byte aligned. | |
95 | ;; mov r15,r1 | |
96 | ;; .align 2 ! Insert aligning nop if needed. | |
97 | ;; mov #(.Lstart - .Lend),r15 ! Enter atomic sequence | |
98 | ;;.Lstart: | |
99 | ;; mov.l @r4,r2 ! read value | |
100 | ;; add r2,r5 ! modify value | |
101 | ;; mov.l r5,@r4 ! write-back | |
102 | ;;.Lend: | |
103 | ;; mov r1,r15 ! Exit atomic sequence | |
104 | ;; ! r2 holds the previous value. | |
105 | ;; ! r5 holds the new value. | |
106 | ;; | |
107 | ;; Notice that due to the restrictions of the mova instruction, the .Lend | |
108 | ;; label must always be 4-byte aligned. Aligning the .Lend label would | |
109 | ;; potentially insert a nop after the write-back instruction which could | |
110 | ;; make the sequence to be rewound, although it has already passed the | |
111 | ;; write-back instruction. This would make it execute twice. | |
112 | ;; For correct operation the atomic sequences must not be rewound after | |
113 | ;; they have passed the write-back instruction. | |
114 | ;; | |
7bd76b9c OE |
115 | ;; This is model works only on SH3* and SH4* because the stack pointer (r15) |
116 | ;; is set to an invalid pointer temporarily. SH1* and SH2* CPUs will try | |
117 | ;; to push SR and PC registers on the stack when an interrupt / exception | |
118 | ;; occurs, and thus require the stack pointer (r15) always to be valid. | |
119 | ;; | |
120 | ;; | |
121 | ;; TCB Software Atomics (-matomic-model=soft-tcb) | |
122 | ;; | |
123 | ;; This model is a variation of the gUSA model. The concept of rewindable | |
124 | ;; atomic sequences is the same, but it does not use the stack pointer (r15) | |
125 | ;; for signaling the 'is in atomic sequence' condition. Instead, a variable | |
126 | ;; in the thread control block (TCB) is set to hold the exit point of the | |
127 | ;; atomic sequence. This assumes that the GBR is used as a thread pointer | |
128 | ;; register. The offset of the variable in the TCB to be used must be | |
129 | ;; specified with an additional option 'gbr-offset', such as: | |
130 | ;; -matomic-model=soft-tcb,gbr-offset=4 | |
131 | ;; | |
132 | ;; For this model the following atomic sequence ABI is used. | |
133 | ;; | |
134 | ;; @(#x,gbr) == 0: Execution context is not in an atomic sequence. | |
135 | ;; | |
136 | ;; @(#x,gbr) != 0: Execution context is in an atomic sequence. In this | |
137 | ;; case the following applies: | |
138 | ;; | |
139 | ;; @(#x,gbr): PC of the first instruction after the atomic | |
140 | ;; write-back instruction (exit point). | |
141 | ;; | |
142 | ;; r1: Negative byte length of the atomic sequence. | |
143 | ;; The entry point PC of the sequence can be | |
144 | ;; determined by doing @(#x,gbr) + r1 | |
145 | ;; | |
146 | ;; Note: #x is the user specified gbr-offset. | |
147 | ;; | |
148 | ;; | |
149 | ;; Interrupt-Flipping Software Atomics (-matomic-model=soft-imask) | |
150 | ;; | |
151 | ;; This model achieves atomicity by temporarily disabling interrupts for | |
152 | ;; the duration of the atomic sequence. This works only when the program | |
153 | ;; runs in privileged mode but does not require any support from the | |
154 | ;; interrupt / exception handling code. There is no particular ABI. | |
155 | ;; To disable interrupts the SR.IMASK bits are set to '1111'. | |
156 | ;; This method is not as efficient as the other software atomic models, | |
157 | ;; since loading and storing SR (in order to flip interrupts on / off) | |
158 | ;; requires using multi-cycle instructions. Moreover, it can potentially | |
159 | ;; increase the interrupt latency which might be important for hard-realtime | |
160 | ;; applications. | |
161 | ;; | |
162 | ;; | |
163 | ;; Compatibility Notes | |
164 | ;; | |
165 | ;; On single-core SH4A CPUs software atomic aware interrupt / exception code | |
166 | ;; is actually compatible with user code that utilizes hardware atomics. | |
167 | ;; Since SImode hardware atomic sequences are more compact on SH4A they are | |
168 | ;; always used, regardless of the selected atomic model. This atomic model | |
169 | ;; mixing can be disabled by setting the 'strict' flag, like: | |
170 | ;; -matomic-model=soft-gusa,strict | |
171 | ;; | |
172 | ;; The software atomic models are generally compatible with each other, | |
173 | ;; but the interrupt / exception handling code has to support both gUSA and | |
174 | ;; TCB models. | |
175 | ;; | |
c11394f8 | 176 | ;; The current atomic support is limited to QImode, HImode and SImode |
f3322315 OE |
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. | |
7768ec4c KK |
181 | |
182 | (define_c_enum "unspec" [ | |
183 | UNSPEC_ATOMIC | |
184 | ]) | |
185 | ||
186 | (define_c_enum "unspecv" [ | |
187 | UNSPECV_CMPXCHG_1 | |
188 | UNSPECV_CMPXCHG_2 | |
189 | UNSPECV_CMPXCHG_3 | |
190 | ]) | |
191 | ||
7768ec4c KK |
192 | (define_mode_attr i124extend_insn [(QI "exts.b") (HI "exts.w") (SI "mov")]) |
193 | ||
194 | (define_code_iterator FETCHOP [plus minus ior xor and]) | |
195 | (define_code_attr fetchop_name | |
7768ec4c KK |
196 | [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")]) |
197 | ||
c11394f8 OE |
198 | ;;------------------------------------------------------------------------------ |
199 | ;; comapre and swap | |
200 | ||
c761dca1 OE |
201 | ;; Only the hard_llcs SImode patterns can use an I08 for the comparison |
202 | ;; or for the new swapped in value. | |
203 | (define_predicate "atomic_arith_operand_0" | |
204 | (and (match_code "subreg,reg,const_int") | |
205 | (ior (match_operand 0 "arith_reg_operand") | |
206 | (and (match_test "satisfies_constraint_I08 (op)") | |
207 | (match_test "mode == SImode") | |
208 | (ior (match_test "TARGET_ATOMIC_HARD_LLCS") | |
209 | (match_test "TARGET_ATOMIC_ANY && TARGET_SH4A | |
210 | && !TARGET_ATOMIC_STRICT")))))) | |
211 | ||
2fdc0399 OE |
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")) | |
2fdc0399 OE |
220 | (match_operand 0 "short_displacement_mem_operand"))))) |
221 | ||
7768ec4c | 222 | (define_expand "atomic_compare_and_swap<mode>" |
c761dca1 OE |
223 | [(match_operand:SI 0 "arith_reg_dest") ;; bool success output |
224 | (match_operand:QIHISI 1 "arith_reg_dest") ;; oldval output | |
2fdc0399 | 225 | (match_operand:QIHISI 2 "atomic_mem_operand_0") ;; memory |
c761dca1 OE |
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 | |
7bd76b9c | 231 | "TARGET_ATOMIC_ANY" |
7768ec4c | 232 | { |
2fdc0399 | 233 | rtx mem = operands[2]; |
c11394f8 OE |
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; | |
238 | ||
7bd76b9c | 239 | if (TARGET_ATOMIC_HARD_LLCS |
f3ca7111 | 240 | || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) |
2fdc0399 | 241 | atomic_insn = gen_atomic_compare_and_swap<mode>_hard (old_val, mem, |
7fa4bf9b | 242 | exp_val, new_val); |
7bd76b9c | 243 | else if (TARGET_ATOMIC_SOFT_GUSA) |
2fdc0399 | 244 | atomic_insn = gen_atomic_compare_and_swap<mode>_soft_gusa (old_val, mem, |
7bd76b9c OE |
245 | exp_val, new_val); |
246 | else if (TARGET_ATOMIC_SOFT_TCB) | |
2fdc0399 | 247 | atomic_insn = gen_atomic_compare_and_swap<mode>_soft_tcb (old_val, mem, |
7bd76b9c OE |
248 | exp_val, new_val, TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX); |
249 | else if (TARGET_ATOMIC_SOFT_IMASK) | |
2fdc0399 | 250 | atomic_insn = gen_atomic_compare_and_swap<mode>_soft_imask (old_val, mem, |
7bd76b9c | 251 | exp_val, new_val); |
c11394f8 | 252 | else |
7bd76b9c OE |
253 | FAIL; |
254 | ||
c11394f8 | 255 | emit_insn (atomic_insn); |
7768ec4c | 256 | |
7768ec4c KK |
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])); | |
349e6f05 | 263 | emit_insn (gen_movsi (operands[0], gen_rtx_REG (SImode, T_REG))); |
7768ec4c KK |
264 | DONE; |
265 | }) | |
266 | ||
2fdc0399 | 267 | (define_insn_and_split "atomic_compare_and_swapsi_hard" |
c761dca1 | 268 | [(set (match_operand:SI 0 "arith_reg_dest" "=&r") |
c11394f8 | 269 | (unspec_volatile:SI |
2fdc0399 | 270 | [(match_operand:SI 1 "atomic_mem_operand_0" "=Sra") |
c11394f8 OE |
271 | (match_operand:SI 2 "arith_operand" "rI08") |
272 | (match_operand:SI 3 "arith_operand" "rI08")] | |
273 | UNSPECV_CMPXCHG_1)) | |
2fdc0399 | 274 | (set (match_dup 1) |
c11394f8 OE |
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))] | |
7bd76b9c | 279 | "TARGET_ATOMIC_HARD_LLCS |
f3ca7111 | 280 | || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" |
c11394f8 | 281 | { |
2fdc0399 | 282 | return "\r0: movli.l %1,r0" "\n" |
c11394f8 OE |
283 | " cmp/eq %2,r0" "\n" |
284 | " bf{.|/}s 0f" "\n" | |
285 | " mov r0,%0" "\n" | |
286 | " mov %3,r0" "\n" | |
2fdc0399 | 287 | " movco.l r0,%1" "\n" |
c11394f8 OE |
288 | " bf 0b" "\n" |
289 | "0:"; | |
2fdc0399 OE |
290 | } |
291 | "&& can_create_pseudo_p () && !satisfies_constraint_I08 (operands[2])" | |
292 | [(const_int 0)] | |
293 | { | |
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, | |
c483db37 | 297 | prev_nonnote_nondebug_insn_bb); |
2fdc0399 OE |
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; | |
c11394f8 OE |
306 | } |
307 | [(set_attr "length" "14")]) | |
308 | ||
2fdc0399 OE |
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)] | |
330 | { | |
331 | rtx i = gen_atomic_compare_and_swap<mode>_hard_1 ( | |
332 | operands[0], XEXP (operands[1], 0), operands[2], operands[3]); | |
333 | ||
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); | |
339 | }) | |
340 | ||
341 | (define_insn "atomic_compare_and_swap<mode>_hard_1" | |
c761dca1 | 342 | [(set (match_operand:SI 0 "arith_reg_dest" "=&r") |
c11394f8 | 343 | (unspec_volatile:SI |
c761dca1 OE |
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")] | |
c11394f8 | 347 | UNSPECV_CMPXCHG_1)) |
7fa4bf9b OE |
348 | (set (mem:QIHI (match_dup 1)) |
349 | (unspec_volatile:QIHI [(const_int 0)] UNSPECV_CMPXCHG_2)) | |
c11394f8 OE |
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"))] | |
7bd76b9c | 356 | "TARGET_ATOMIC_HARD_LLCS" |
c11394f8 OE |
357 | { |
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" | |
7fa4bf9b OE |
366 | " mov.<bw> @%1,%0" "\n" |
367 | " mov.<bw> %3,@%1" "\n" | |
c11394f8 OE |
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:"; | |
374 | } | |
375 | [(set_attr "length" "30")]) | |
376 | ||
7bd76b9c | 377 | (define_insn "atomic_compare_and_swap<mode>_soft_gusa" |
c761dca1 | 378 | [(set (match_operand:SI 0 "arith_reg_dest" "=&u") |
7768ec4c | 379 | (unspec_volatile:SI |
2fdc0399 | 380 | [(match_operand:QIHISI 1 "atomic_mem_operand_0" "=AraAdd") |
c761dca1 OE |
381 | (match_operand:QIHISI 2 "arith_reg_operand" "u") |
382 | (match_operand:QIHISI 3 "arith_reg_operand" "u")] | |
7768ec4c | 383 | UNSPECV_CMPXCHG_1)) |
2fdc0399 | 384 | (set (match_dup 1) |
7fa4bf9b | 385 | (unspec_volatile:QIHISI [(const_int 0)] UNSPECV_CMPXCHG_2)) |
349e6f05 OE |
386 | (set (reg:SI T_REG) |
387 | (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3)) | |
7768ec4c KK |
388 | (clobber (match_scratch:SI 4 "=&u")) |
389 | (clobber (reg:SI R0_REG)) | |
390 | (clobber (reg:SI R1_REG))] | |
7bd76b9c | 391 | "TARGET_ATOMIC_SOFT_GUSA" |
7768ec4c | 392 | { |
c11394f8 | 393 | return "\r mova 1f,r0" "\n" |
f3322315 OE |
394 | " <i124extend_insn> %2,%4" "\n" |
395 | " .align 2" "\n" | |
396 | " mov r15,r1" "\n" | |
397 | " mov #(0f-1f),r15" "\n" | |
2fdc0399 | 398 | "0: mov.<bwl> %1,%0" "\n" |
f3322315 OE |
399 | " cmp/eq %0,%4" "\n" |
400 | " bf 1f" "\n" | |
2fdc0399 | 401 | " mov.<bwl> %3,%1" "\n" |
f3322315 OE |
402 | "1: mov r1,r15"; |
403 | } | |
7768ec4c KK |
404 | [(set_attr "length" "20")]) |
405 | ||
7bd76b9c | 406 | (define_insn "atomic_compare_and_swap<mode>_soft_tcb" |
c761dca1 | 407 | [(set (match_operand:SI 0 "arith_reg_dest" "=&r") |
7bd76b9c | 408 | (unspec_volatile:SI |
2fdc0399 | 409 | [(match_operand:QIHISI 1 "atomic_mem_operand_0" "=SraSdd") |
c761dca1 OE |
410 | (match_operand:QIHISI 2 "arith_reg_operand" "r") |
411 | (match_operand:QIHISI 3 "arith_reg_operand" "r")] | |
7bd76b9c | 412 | UNSPECV_CMPXCHG_1)) |
2fdc0399 | 413 | (set (match_dup 1) |
7bd76b9c OE |
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" | |
422 | { | |
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" | |
2fdc0399 | 428 | "0: mov.<bwl> %1,%0" "\n" |
7bd76b9c OE |
429 | " mov #0,r0" "\n" |
430 | " cmp/eq %0,%5" "\n" | |
431 | " bf 1f" "\n" | |
2fdc0399 | 432 | " mov.<bwl> %3,%1" "\n" |
7bd76b9c OE |
433 | "1: mov.l r0,@(%O4,gbr)"; |
434 | } | |
435 | [(set_attr "length" "22")]) | |
436 | ||
437 | (define_insn "atomic_compare_and_swap<mode>_soft_imask" | |
c761dca1 | 438 | [(set (match_operand:SI 0 "arith_reg_dest" "=&z") |
7bd76b9c | 439 | (unspec_volatile:SI |
2fdc0399 | 440 | [(match_operand:QIHISI 1 "atomic_mem_operand_0" "=SraSdd") |
c761dca1 OE |
441 | (match_operand:QIHISI 2 "arith_reg_operand" "r") |
442 | (match_operand:QIHISI 3 "arith_reg_operand" "r")] | |
7bd76b9c | 443 | UNSPECV_CMPXCHG_1)) |
2fdc0399 | 444 | (set (match_dup 1) |
7bd76b9c OE |
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" | |
451 | { | |
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" | |
2fdc0399 | 463 | " mov.<bwl> %1,%0" "\n" |
7bd76b9c OE |
464 | " cmp/eq %4,%0" "\n" |
465 | " bf 1f" "\n" | |
2fdc0399 | 466 | " mov.<bwl> %3,%1" "\n" |
7bd76b9c OE |
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" | |
2fdc0399 | 475 | " mov.<bwl> %1,%0" "\n" |
7bd76b9c OE |
476 | " cmp/eq %4,%0" "\n" |
477 | " bst #0,%5" "\n" | |
478 | " bf 1f" "\n" | |
2fdc0399 | 479 | " mov.<bwl> %3,%1" "\n" |
7bd76b9c OE |
480 | "1: ldc %5,sr"; |
481 | } | |
482 | [(set (attr "length") (if_then_else (match_test "!TARGET_SH2A") | |
483 | (const_string "24") | |
484 | (const_string "22")))]) | |
485 | ||
c11394f8 OE |
486 | ;;------------------------------------------------------------------------------ |
487 | ;; read - write - return old value | |
488 | ||
b5ea8036 | 489 | (define_expand "atomic_exchange<mode>" |
c761dca1 | 490 | [(match_operand:QIHISI 0 "arith_reg_dest") ;; oldval output |
2fdc0399 | 491 | (match_operand:QIHISI 1 "atomic_mem_operand_0") ;; memory |
c761dca1 OE |
492 | (match_operand:QIHISI 2 "atomic_arith_operand_0") ;; newval input |
493 | (match_operand:SI 3 "const_int_operand")] ;; memory model | |
7bd76b9c | 494 | "TARGET_ATOMIC_ANY" |
b5ea8036 | 495 | { |
2fdc0399 | 496 | rtx mem = operands[1]; |
c11394f8 OE |
497 | rtx val = operands[2]; |
498 | rtx atomic_insn; | |
499 | ||
7bd76b9c | 500 | if (TARGET_ATOMIC_HARD_LLCS |
f3ca7111 | 501 | || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) |
2fdc0399 | 502 | atomic_insn = gen_atomic_exchange<mode>_hard (operands[0], mem, val); |
7bd76b9c | 503 | else if (TARGET_ATOMIC_SOFT_GUSA) |
2fdc0399 | 504 | atomic_insn = gen_atomic_exchange<mode>_soft_gusa (operands[0], mem, val); |
7bd76b9c | 505 | else if (TARGET_ATOMIC_SOFT_TCB) |
2fdc0399 | 506 | atomic_insn = gen_atomic_exchange<mode>_soft_tcb (operands[0], mem, val, |
7bd76b9c OE |
507 | TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX); |
508 | else if (TARGET_ATOMIC_SOFT_IMASK) | |
2fdc0399 | 509 | atomic_insn = gen_atomic_exchange<mode>_soft_imask (operands[0], mem, val); |
c11394f8 | 510 | else |
7bd76b9c | 511 | FAIL; |
c11394f8 OE |
512 | |
513 | emit_insn (atomic_insn); | |
514 | ||
b5ea8036 OE |
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; | |
522 | }) | |
523 | ||
c11394f8 | 524 | (define_insn "atomic_exchangesi_hard" |
c761dca1 | 525 | [(set (match_operand:SI 0 "arith_reg_dest" "=&r") |
2fdc0399 OE |
526 | (match_operand:SI 1 "atomic_mem_operand_0" "=Sra")) |
527 | (set (match_dup 1) | |
c11394f8 OE |
528 | (unspec:SI |
529 | [(match_operand:SI 2 "arith_operand" "rI08")] UNSPEC_ATOMIC)) | |
659a6a94 | 530 | (set (reg:SI T_REG) (const_int 1)) |
c11394f8 | 531 | (clobber (reg:SI R0_REG))] |
7bd76b9c | 532 | "TARGET_ATOMIC_HARD_LLCS |
f3ca7111 | 533 | || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" |
c11394f8 | 534 | { |
2fdc0399 | 535 | return "\r0: movli.l %1,r0" "\n" |
c11394f8 OE |
536 | " mov r0,%0" "\n" |
537 | " mov %2,r0" "\n" | |
2fdc0399 | 538 | " movco.l r0,%1" "\n" |
c11394f8 OE |
539 | " bf 0b"; |
540 | } | |
541 | [(set_attr "length" "10")]) | |
542 | ||
2fdc0399 OE |
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)] | |
560 | { | |
561 | rtx i = gen_atomic_exchange<mode>_hard_1 (operands[0], XEXP (operands[1], 0), | |
562 | operands[2]); | |
563 | ||
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); | |
569 | }) | |
570 | ||
571 | (define_insn "atomic_exchange<mode>_hard_1" | |
c761dca1 OE |
572 | [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r") |
573 | (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))) | |
7fa4bf9b OE |
574 | (set (mem:QIHI (match_dup 1)) |
575 | (unspec:QIHI | |
c761dca1 | 576 | [(match_operand:QIHI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC)) |
659a6a94 | 577 | (set (reg:SI T_REG) (const_int 1)) |
c11394f8 OE |
578 | (clobber (reg:SI R0_REG)) |
579 | (clobber (match_scratch:SI 3 "=&r")) | |
580 | (clobber (match_scratch:SI 4 "=1"))] | |
7bd76b9c | 581 | "TARGET_ATOMIC_HARD_LLCS" |
c11394f8 OE |
582 | { |
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" | |
7fa4bf9b OE |
590 | " mov.<bw> @%1,%0" "\n" |
591 | " mov.<bw> %2,@%1" "\n" | |
c11394f8 OE |
592 | " mov.l @r15+,r0" "\n" |
593 | " movco.l r0,@%3" "\n" | |
594 | " bf 0b"; | |
595 | } | |
596 | [(set_attr "length" "24")]) | |
597 | ||
7bd76b9c | 598 | (define_insn "atomic_exchange<mode>_soft_gusa" |
c761dca1 | 599 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u") |
2fdc0399 OE |
600 | (match_operand:QIHISI 1 "atomic_mem_operand_0" "=AraAdd")) |
601 | (set (match_dup 1) | |
7fa4bf9b | 602 | (unspec:QIHISI |
c761dca1 | 603 | [(match_operand:QIHISI 2 "arith_reg_operand" "u")] UNSPEC_ATOMIC)) |
b5ea8036 OE |
604 | (clobber (reg:SI R0_REG)) |
605 | (clobber (reg:SI R1_REG))] | |
7bd76b9c | 606 | "TARGET_ATOMIC_SOFT_GUSA" |
b5ea8036 | 607 | { |
c11394f8 | 608 | return "\r mova 1f,r0" "\n" |
b5ea8036 OE |
609 | " .align 2" "\n" |
610 | " mov r15,r1" "\n" | |
611 | " mov #(0f-1f),r15" "\n" | |
2fdc0399 OE |
612 | "0: mov.<bwl> %1,%0" "\n" |
613 | " mov.<bwl> %2,%1" "\n" | |
b5ea8036 OE |
614 | "1: mov r1,r15"; |
615 | } | |
616 | [(set_attr "length" "14")]) | |
617 | ||
7bd76b9c | 618 | (define_insn "atomic_exchange<mode>_soft_tcb" |
c761dca1 | 619 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r") |
2fdc0399 OE |
620 | (match_operand:QIHISI 1 "atomic_mem_operand_0" "=SraSdd")) |
621 | (set (match_dup 1) | |
7bd76b9c | 622 | (unspec:QIHISI |
c761dca1 | 623 | [(match_operand:QIHISI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC)) |
7bd76b9c OE |
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" | |
628 | { | |
629 | return "\r mova 1f,r0" "\n" | |
630 | " mov #(0f-1f),r1" "\n" | |
631 | " .align 2" "\n" | |
632 | " mov.l r0,@(%O3,gbr)" "\n" | |
2fdc0399 | 633 | "0: mov.<bwl> %1,%0" "\n" |
7bd76b9c | 634 | " mov #0,r0" "\n" |
2fdc0399 | 635 | " mov.<bwl> %2,%1" "\n" |
7bd76b9c OE |
636 | "1: mov.l r0,@(%O3,gbr)"; |
637 | } | |
638 | [(set_attr "length" "16")]) | |
639 | ||
640 | (define_insn "atomic_exchange<mode>_soft_imask" | |
c761dca1 | 641 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z") |
2fdc0399 OE |
642 | (match_operand:QIHISI 1 "atomic_mem_operand_0" "=SraSdd")) |
643 | (set (match_dup 1) | |
7bd76b9c | 644 | (unspec:QIHISI |
c761dca1 | 645 | [(match_operand:QIHISI 2 "arith_reg_operand" "r")] UNSPEC_ATOMIC)) |
7bd76b9c OE |
646 | (clobber (match_scratch:SI 3 "=&r"))] |
647 | "TARGET_ATOMIC_SOFT_IMASK" | |
648 | { | |
649 | return "\r stc sr,%0" "\n" | |
650 | " mov %0,%3" "\n" | |
651 | " or #0xF0,%0" "\n" | |
652 | " ldc %0,sr" "\n" | |
2fdc0399 OE |
653 | " mov.<bwl> %1,%0" "\n" |
654 | " mov.<bwl> %2,%1" "\n" | |
7bd76b9c OE |
655 | " ldc %3,sr"; |
656 | } | |
657 | [(set_attr "length" "14")]) | |
658 | ||
c11394f8 OE |
659 | ;;------------------------------------------------------------------------------ |
660 | ;; read - add|sub|or|and|xor|nand - write - return old value | |
661 | ||
c761dca1 OE |
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)")))) | |
668 | ||
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")))))) | |
681 | ||
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")]) | |
686 | ||
687 | (define_code_attr fetchop_constraint_1_llcs | |
688 | [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")]) | |
689 | ||
690 | (define_code_attr fetchop_constraint_1_gusa | |
691 | [(plus "uI08") (minus "u") (ior "u") (xor "u") (and "u")]) | |
692 | ||
693 | (define_code_attr fetchop_constraint_1_tcb | |
694 | [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")]) | |
695 | ||
696 | (define_code_attr fetchop_constraint_1_imask | |
697 | [(plus "rI08") (minus "r") (ior "rK08") (xor "rK08") (and "rK08")]) | |
698 | ||
2fdc0399 OE |
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)") | |
2fdc0399 OE |
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")) | |
21f65dc8 | 717 | (ior (match_operand 0 "short_displacement_mem_operand") |
2fdc0399 OE |
718 | (match_operand 0 "gbr_address_mem")))))) |
719 | ||
7768ec4c | 720 | (define_expand "atomic_fetch_<fetchop_name><mode>" |
c761dca1 | 721 | [(set (match_operand:QIHISI 0 "arith_reg_dest") |
2fdc0399 | 722 | (match_operand:QIHISI 1 "atomic_mem_operand_1")) |
7768ec4c | 723 | (set (match_dup 1) |
7fa4bf9b OE |
724 | (unspec:QIHISI |
725 | [(FETCHOP:QIHISI (match_dup 1) | |
c761dca1 | 726 | (match_operand:QIHISI 2 "<fetchop_predicate_1>"))] |
7768ec4c | 727 | UNSPEC_ATOMIC)) |
c761dca1 | 728 | (match_operand:SI 3 "const_int_operand")] |
7bd76b9c | 729 | "TARGET_ATOMIC_ANY" |
7768ec4c | 730 | { |
2fdc0399 | 731 | rtx mem = operands[1]; |
c11394f8 OE |
732 | rtx atomic_insn; |
733 | ||
7bd76b9c | 734 | if (TARGET_ATOMIC_HARD_LLCS |
f3ca7111 | 735 | || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) |
2fdc0399 | 736 | atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_hard (operands[0], mem, |
c11394f8 | 737 | operands[2]); |
7bd76b9c OE |
738 | else if (TARGET_ATOMIC_SOFT_GUSA) |
739 | atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_gusa (operands[0], | |
2fdc0399 | 740 | mem, operands[2]); |
7bd76b9c OE |
741 | else if (TARGET_ATOMIC_SOFT_TCB) |
742 | atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_tcb (operands[0], | |
2fdc0399 | 743 | mem, operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX); |
7bd76b9c OE |
744 | else if (TARGET_ATOMIC_SOFT_IMASK) |
745 | atomic_insn = gen_atomic_fetch_<fetchop_name><mode>_soft_imask (operands[0], | |
2fdc0399 | 746 | mem, operands[2]); |
c11394f8 | 747 | else |
7bd76b9c OE |
748 | FAIL; |
749 | ||
c11394f8 | 750 | emit_insn (atomic_insn); |
7768ec4c | 751 | |
7768ec4c KK |
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; | |
759 | }) | |
760 | ||
3548abca | 761 | (define_insn_and_split "atomic_fetch_<fetchop_name>si_hard" |
c761dca1 | 762 | [(set (match_operand:SI 0 "arith_reg_dest" "=&r") |
2fdc0399 OE |
763 | (match_operand:SI 1 "atomic_mem_operand_1" "=Sra")) |
764 | (set (match_dup 1) | |
c11394f8 | 765 | (unspec:SI |
2fdc0399 | 766 | [(FETCHOP:SI (match_dup 1) |
c761dca1 OE |
767 | (match_operand:SI 2 "<fetchop_predicate_1>" |
768 | "<fetchop_constraint_1_llcs>"))] | |
c11394f8 | 769 | UNSPEC_ATOMIC)) |
659a6a94 | 770 | (set (reg:SI T_REG) (const_int 1)) |
c11394f8 | 771 | (clobber (reg:SI R0_REG))] |
7bd76b9c | 772 | "TARGET_ATOMIC_HARD_LLCS |
f3ca7111 | 773 | || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" |
c11394f8 | 774 | { |
2fdc0399 | 775 | return "\r0: movli.l %1,r0" "\n" |
c11394f8 OE |
776 | " mov r0,%0" "\n" |
777 | " <fetchop_name> %2,r0" "\n" | |
2fdc0399 | 778 | " movco.l r0,%1" "\n" |
c11394f8 | 779 | " bf 0b"; |
3548abca OE |
780 | } |
781 | "&& can_create_pseudo_p () && optimize | |
782 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
783 | [(const_int 0)] | |
784 | { | |
785 | emit_insn (gen_atomic_<fetchop_name>_fetchsi_hard (gen_reg_rtx (SImode), | |
786 | operands[1], operands[2])); | |
c11394f8 OE |
787 | } |
788 | [(set_attr "length" "10")]) | |
789 | ||
2b8427ca | 790 | ;; Combine pattern for xor (val, -1) / nand (val, -1). |
3548abca | 791 | (define_insn_and_split "atomic_fetch_notsi_hard" |
2b8427ca | 792 | [(set (match_operand:SI 0 "arith_reg_dest" "=&r") |
2fdc0399 OE |
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)) | |
2b8427ca OE |
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)" | |
800 | { | |
2fdc0399 | 801 | return "\r0: movli.l %1,r0" "\n" |
2b8427ca OE |
802 | " mov r0,%0" "\n" |
803 | " not r0,r0" "\n" | |
2fdc0399 | 804 | " movco.l r0,%1" "\n" |
2b8427ca | 805 | " bf 0b"; |
3548abca OE |
806 | } |
807 | "&& can_create_pseudo_p () && optimize | |
808 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
809 | [(const_int 0)] | |
810 | { | |
811 | emit_insn (gen_atomic_not_fetchsi_hard (gen_reg_rtx (SImode), operands[1])); | |
2b8427ca OE |
812 | } |
813 | [(set_attr "length" "10")]) | |
814 | ||
2fdc0399 OE |
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. | |
3548abca | 820 | (define_insn_and_split "atomic_fetch_<fetchop_name><mode>_hard" |
2fdc0399 OE |
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)] | |
834 | { | |
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]); | |
842 | ||
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 | } | |
850 | }) | |
851 | ||
852 | (define_insn "atomic_fetch_<fetchop_name><mode>_hard_1" | |
c761dca1 OE |
853 | [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r") |
854 | (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))) | |
7fa4bf9b OE |
855 | (set (mem:QIHI (match_dup 1)) |
856 | (unspec:QIHI | |
857 | [(FETCHOP:QIHI (mem:QIHI (match_dup 1)) | |
c761dca1 OE |
858 | (match_operand:QIHI 2 "<fetchop_predicate_1>" |
859 | "<fetchop_constraint_1_llcs>"))] | |
c11394f8 | 860 | UNSPEC_ATOMIC)) |
659a6a94 | 861 | (set (reg:SI T_REG) (const_int 1)) |
c11394f8 OE |
862 | (clobber (reg:SI R0_REG)) |
863 | (clobber (match_scratch:SI 3 "=&r")) | |
864 | (clobber (match_scratch:SI 4 "=1"))] | |
7bd76b9c | 865 | "TARGET_ATOMIC_HARD_LLCS" |
c11394f8 OE |
866 | { |
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" | |
7fa4bf9b | 874 | " mov.<bw> @%1,r0" "\n" |
c11394f8 OE |
875 | " mov r0,%0" "\n" |
876 | " <fetchop_name> %2,r0" "\n" | |
7fa4bf9b | 877 | " mov.<bw> r0,@%1" "\n" |
c11394f8 OE |
878 | " mov.l @r15+,r0" "\n" |
879 | " movco.l r0,@%3" "\n" | |
880 | " bf 0b"; | |
3548abca | 881 | } |
2fdc0399 OE |
882 | [(set_attr "length" "28")]) |
883 | ||
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" | |
3548abca OE |
900 | [(const_int 0)] |
901 | { | |
2fdc0399 OE |
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); | |
909 | }) | |
c11394f8 | 910 | |
2fdc0399 | 911 | (define_insn "atomic_<fetchop_name><mode>_hard_1" |
3548abca OE |
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" | |
923 | { | |
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"; | |
937 | } | |
938 | [(set_attr "length" "26")]) | |
939 | ||
2b8427ca | 940 | ;; Combine pattern for xor (val, -1) / nand (val, -1). |
3548abca | 941 | (define_insn_and_split "atomic_fetch_not<mode>_hard" |
2b8427ca OE |
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" | |
951 | { | |
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"; | |
3548abca OE |
965 | } |
966 | "&& can_create_pseudo_p () && optimize | |
967 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
968 | [(const_int 0)] | |
969 | { | |
2fdc0399 OE |
970 | rtx i = gen_atomic_not<mode>_hard (operands[1]); |
971 | ||
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); | |
3548abca OE |
978 | } |
979 | [(set_attr "length" "26")]) | |
980 | ||
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" | |
989 | { | |
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"; | |
2b8427ca OE |
1003 | } |
1004 | [(set_attr "length" "26")]) | |
1005 | ||
3548abca | 1006 | (define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_gusa" |
c761dca1 | 1007 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u") |
2fdc0399 OE |
1008 | (match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd")) |
1009 | (set (match_dup 1) | |
7fa4bf9b | 1010 | (unspec:QIHISI |
c761dca1 | 1011 | [(FETCHOP:QIHISI |
2fdc0399 | 1012 | (match_dup 1) |
c761dca1 OE |
1013 | (match_operand:QIHISI 2 "<fetchop_predicate_1>" |
1014 | "<fetchop_constraint_1_gusa>"))] | |
7768ec4c | 1015 | UNSPEC_ATOMIC)) |
7fa4bf9b | 1016 | (clobber (match_scratch:QIHISI 3 "=&u")) |
7768ec4c KK |
1017 | (clobber (reg:SI R0_REG)) |
1018 | (clobber (reg:SI R1_REG))] | |
7bd76b9c | 1019 | "TARGET_ATOMIC_SOFT_GUSA" |
7768ec4c | 1020 | { |
c11394f8 | 1021 | return "\r mova 1f,r0" "\n" |
f3322315 OE |
1022 | " .align 2" "\n" |
1023 | " mov r15,r1" "\n" | |
1024 | " mov #(0f-1f),r15" "\n" | |
2fdc0399 | 1025 | "0: mov.<bwl> %1,%0" "\n" |
f3322315 OE |
1026 | " mov %0,%3" "\n" |
1027 | " <fetchop_name> %2,%3" "\n" | |
2fdc0399 | 1028 | " mov.<bwl> %3,%1" "\n" |
f3322315 | 1029 | "1: mov r1,r15"; |
3548abca OE |
1030 | } |
1031 | "&& can_create_pseudo_p () && optimize | |
1032 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
1033 | [(const_int 0)] | |
1034 | { | |
1035 | emit_insn (gen_atomic_<fetchop_name>_fetch<mode>_soft_gusa ( | |
1036 | gen_reg_rtx (<MODE>mode), operands[1], operands[2])); | |
f3322315 | 1037 | } |
7768ec4c KK |
1038 | [(set_attr "length" "18")]) |
1039 | ||
2b8427ca | 1040 | ;; Combine pattern for xor (val, -1) / nand (val, -1). |
3548abca | 1041 | (define_insn_and_split "atomic_fetch_not<mode>_soft_gusa" |
2b8427ca | 1042 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u") |
2fdc0399 OE |
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)) | |
2b8427ca OE |
1046 | (clobber (match_scratch:QIHISI 2 "=&u")) |
1047 | (clobber (reg:SI R0_REG)) | |
1048 | (clobber (reg:SI R1_REG))] | |
1049 | "TARGET_ATOMIC_SOFT_GUSA" | |
1050 | { | |
1051 | return "\r mova 1f,r0" "\n" | |
1052 | " mov r15,r1" "\n" | |
1053 | " .align 2" "\n" | |
1054 | " mov #(0f-1f),r15" "\n" | |
2fdc0399 | 1055 | "0: mov.<bwl> %1,%0" "\n" |
2b8427ca | 1056 | " not %0,%2" "\n" |
2fdc0399 | 1057 | " mov.<bwl> %2,%1" "\n" |
2b8427ca | 1058 | "1: mov r1,r15"; |
3548abca OE |
1059 | } |
1060 | "&& can_create_pseudo_p () && optimize | |
1061 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
1062 | [(const_int 0)] | |
1063 | { | |
1064 | emit_insn (gen_atomic_not_fetch<mode>_soft_gusa (gen_reg_rtx (<MODE>mode), | |
1065 | operands[1])); | |
2b8427ca OE |
1066 | } |
1067 | [(set_attr "length" "16")]) | |
1068 | ||
3548abca | 1069 | (define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_tcb" |
c761dca1 | 1070 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r") |
2fdc0399 OE |
1071 | (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")) |
1072 | (set (match_dup 1) | |
7bd76b9c | 1073 | (unspec:QIHISI |
c761dca1 | 1074 | [(FETCHOP:QIHISI |
2fdc0399 | 1075 | (match_dup 1) |
c761dca1 OE |
1076 | (match_operand:QIHISI 2 "<fetchop_predicate_1>" |
1077 | "<fetchop_constraint_1_tcb>"))] | |
7bd76b9c OE |
1078 | UNSPEC_ATOMIC)) |
1079 | (use (match_operand:SI 3 "gbr_displacement")) | |
7bd76b9c OE |
1080 | (clobber (reg:SI R0_REG)) |
1081 | (clobber (reg:SI R1_REG))] | |
1082 | "TARGET_ATOMIC_SOFT_TCB" | |
1083 | { | |
1084 | return "\r mova 1f,r0" "\n" | |
7bd76b9c | 1085 | " .align 2" "\n" |
c761dca1 | 1086 | " mov #(0f-1f),r1" "\n" |
7bd76b9c | 1087 | " mov.l r0,@(%O3,gbr)" "\n" |
2fdc0399 | 1088 | "0: mov.<bwl> %1,r0" "\n" |
c761dca1 OE |
1089 | " mov r0,%0" "\n" |
1090 | " <fetchop_name> %2,r0" "\n" | |
2fdc0399 | 1091 | " mov.<bwl> r0,%1" "\n" |
c761dca1 OE |
1092 | "1: mov #0,r0" "\n" |
1093 | " mov.l r0,@(%O3,gbr)"; | |
3548abca OE |
1094 | } |
1095 | "&& can_create_pseudo_p () && optimize | |
1096 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
1097 | [(const_int 0)] | |
1098 | { | |
1099 | emit_insn (gen_atomic_<fetchop_name><mode>_soft_tcb ( | |
1100 | operands[1], operands[2], operands[3])); | |
7bd76b9c OE |
1101 | } |
1102 | [(set_attr "length" "20")]) | |
1103 | ||
3548abca | 1104 | (define_insn "atomic_<fetchop_name><mode>_soft_tcb" |
2fdc0399 | 1105 | [(set (match_operand:QIHISI 0 "atomic_mem_operand_1" "=SraSdd") |
3548abca OE |
1106 | (unspec:QIHISI |
1107 | [(FETCHOP:QIHISI | |
2fdc0399 | 1108 | (match_dup 0) |
3548abca OE |
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" | |
1116 | { | |
1117 | return "\r mova 1f,r0" "\n" | |
1118 | " mov #(0f-1f),r1" "\n" | |
1119 | " .align 2" "\n" | |
1120 | " mov.l r0,@(%O2,gbr)" "\n" | |
2fdc0399 | 1121 | "0: mov.<bwl> %0,r0" "\n" |
3548abca | 1122 | " <fetchop_name> %1,r0" "\n" |
2fdc0399 | 1123 | " mov.<bwl> r0,%0" "\n" |
3548abca OE |
1124 | "1: mov #0,r0" "\n" |
1125 | " mov.l r0,@(%O2,gbr)"; | |
1126 | } | |
1127 | [(set_attr "length" "18")]) | |
1128 | ||
2b8427ca | 1129 | ;; Combine pattern for xor (val, -1) / nand (val, -1). |
3548abca | 1130 | (define_insn_and_split "atomic_fetch_not<mode>_soft_tcb" |
2b8427ca | 1131 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r") |
2fdc0399 OE |
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)) | |
2b8427ca OE |
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" | |
1139 | { | |
1140 | return "\r mova 1f,r0" "\n" | |
1141 | " .align 2" "\n" | |
1142 | " mov #(0f-1f),r1" "\n" | |
1143 | " mov.l r0,@(%O2,gbr)" "\n" | |
2fdc0399 | 1144 | "0: mov.<bwl> %1,r0" "\n" |
2b8427ca OE |
1145 | " mov r0,%0" "\n" |
1146 | " not r0,r0" "\n" | |
2fdc0399 | 1147 | " mov.<bwl> r0,%1" "\n" |
2b8427ca OE |
1148 | "1: mov #0,r0" "\n" |
1149 | " mov.l r0,@(%O2,gbr)"; | |
3548abca OE |
1150 | } |
1151 | "&& can_create_pseudo_p () && optimize | |
1152 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
1153 | [(const_int 0)] | |
1154 | { | |
1155 | emit_insn (gen_atomic_not<mode>_soft_tcb (operands[1], operands[2])); | |
2b8427ca OE |
1156 | } |
1157 | [(set_attr "length" "20")]) | |
1158 | ||
3548abca | 1159 | (define_insn "atomic_not<mode>_soft_tcb" |
2fdc0399 OE |
1160 | [(set (match_operand:QIHISI 0 "atomic_mem_operand_1" "=SraSdd") |
1161 | (unspec:QIHISI [(not:QIHISI (match_dup 0))] UNSPEC_ATOMIC)) | |
3548abca OE |
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" | |
1166 | { | |
1167 | return "\r mova 1f,r0" "\n" | |
1168 | " mov #(0f-1f),r1" "\n" | |
1169 | " .align 2" "\n" | |
1170 | " mov.l r0,@(%O1,gbr)" "\n" | |
2fdc0399 | 1171 | "0: mov.<bwl> %0,r0" "\n" |
3548abca | 1172 | " not r0,r0" "\n" |
2fdc0399 | 1173 | " mov.<bwl> r0,%0" "\n" |
3548abca OE |
1174 | "1: mov #0,r0" "\n" |
1175 | " mov.l r0,@(%O1,gbr)"; | |
1176 | } | |
1177 | [(set_attr "length" "18")]) | |
1178 | ||
1179 | (define_insn_and_split "atomic_fetch_<fetchop_name><mode>_soft_imask" | |
c761dca1 | 1180 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r") |
2fdc0399 OE |
1181 | (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")) |
1182 | (set (match_dup 1) | |
7bd76b9c | 1183 | (unspec:QIHISI |
c761dca1 | 1184 | [(FETCHOP:QIHISI |
2fdc0399 | 1185 | (match_dup 1) |
c761dca1 OE |
1186 | (match_operand:QIHISI 2 "<fetchop_predicate_1>" |
1187 | "<fetchop_constraint_1_imask>"))] | |
7bd76b9c | 1188 | UNSPEC_ATOMIC)) |
c761dca1 OE |
1189 | (clobber (reg:SI R0_REG)) |
1190 | (clobber (match_scratch:QIHISI 3 "=&r"))] | |
7bd76b9c OE |
1191 | "TARGET_ATOMIC_SOFT_IMASK" |
1192 | { | |
c761dca1 OE |
1193 | return "\r stc sr,r0" "\n" |
1194 | " mov r0,%3" "\n" | |
1195 | " or #0xF0,r0" "\n" | |
1196 | " ldc r0,sr" "\n" | |
2fdc0399 | 1197 | " mov.<bwl> %1,r0" "\n" |
c761dca1 OE |
1198 | " mov r0,%0" "\n" |
1199 | " <fetchop_name> %2,r0" "\n" | |
2fdc0399 | 1200 | " mov.<bwl> r0,%1" "\n" |
c761dca1 | 1201 | " ldc %3,sr"; |
3548abca OE |
1202 | } |
1203 | "&& can_create_pseudo_p () && optimize | |
1204 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
1205 | [(const_int 0)] | |
1206 | { | |
1207 | emit_insn (gen_atomic_<fetchop_name>_fetch<mode>_soft_imask ( | |
1208 | gen_reg_rtx (<MODE>mode), operands[1], operands[2])); | |
7bd76b9c OE |
1209 | } |
1210 | [(set_attr "length" "18")]) | |
1211 | ||
2b8427ca | 1212 | ;; Combine pattern for xor (val, -1) / nand (val, -1). |
3548abca | 1213 | (define_insn_and_split "atomic_fetch_not<mode>_soft_imask" |
2b8427ca | 1214 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r") |
2fdc0399 OE |
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)) | |
2b8427ca OE |
1218 | (clobber (reg:SI R0_REG)) |
1219 | (clobber (match_scratch:QIHISI 2 "=&r"))] | |
1220 | "TARGET_ATOMIC_SOFT_IMASK" | |
1221 | { | |
1222 | return "\r stc sr,r0" "\n" | |
1223 | " mov r0,%2" "\n" | |
1224 | " or #0xF0,r0" "\n" | |
1225 | " ldc r0,sr" "\n" | |
2fdc0399 | 1226 | " mov.<bwl> %1,r0" "\n" |
2b8427ca OE |
1227 | " mov r0,%0" "\n" |
1228 | " not r0,r0" "\n" | |
2fdc0399 | 1229 | " mov.<bwl> r0,%1" "\n" |
2b8427ca | 1230 | " ldc %2,sr"; |
3548abca OE |
1231 | } |
1232 | "&& can_create_pseudo_p () && optimize | |
1233 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
1234 | [(const_int 0)] | |
1235 | { | |
1236 | emit_insn (gen_atomic_not_fetch<mode>_soft_imask (gen_reg_rtx (<MODE>mode), | |
1237 | operands[1])); | |
2b8427ca OE |
1238 | } |
1239 | [(set_attr "length" "18")]) | |
1240 | ||
7768ec4c | 1241 | (define_expand "atomic_fetch_nand<mode>" |
c761dca1 | 1242 | [(set (match_operand:QIHISI 0 "arith_reg_dest") |
2fdc0399 | 1243 | (match_operand:QIHISI 1 "atomic_mem_operand_1")) |
7768ec4c | 1244 | (set (match_dup 1) |
7fa4bf9b OE |
1245 | (unspec:QIHISI |
1246 | [(not:QIHISI (and:QIHISI (match_dup 1) | |
c761dca1 | 1247 | (match_operand:QIHISI 2 "atomic_logical_operand_1")))] |
7768ec4c | 1248 | UNSPEC_ATOMIC)) |
c761dca1 | 1249 | (match_operand:SI 3 "const_int_operand")] |
7bd76b9c | 1250 | "TARGET_ATOMIC_ANY" |
7768ec4c | 1251 | { |
2fdc0399 | 1252 | rtx mem = operands[1]; |
c11394f8 OE |
1253 | rtx atomic_insn; |
1254 | ||
7bd76b9c | 1255 | if (TARGET_ATOMIC_HARD_LLCS |
f3ca7111 | 1256 | || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) |
2fdc0399 | 1257 | atomic_insn = gen_atomic_fetch_nand<mode>_hard (operands[0], mem, |
c11394f8 | 1258 | operands[2]); |
7bd76b9c | 1259 | else if (TARGET_ATOMIC_SOFT_GUSA) |
2fdc0399 | 1260 | atomic_insn = gen_atomic_fetch_nand<mode>_soft_gusa (operands[0], mem, |
7bd76b9c OE |
1261 | operands[2]); |
1262 | else if (TARGET_ATOMIC_SOFT_TCB) | |
2fdc0399 | 1263 | atomic_insn = gen_atomic_fetch_nand<mode>_soft_tcb (operands[0], mem, |
7bd76b9c OE |
1264 | operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX); |
1265 | else if (TARGET_ATOMIC_SOFT_IMASK) | |
2fdc0399 | 1266 | atomic_insn = gen_atomic_fetch_nand<mode>_soft_imask (operands[0], mem, |
7bd76b9c | 1267 | operands[2]); |
c11394f8 | 1268 | else |
7bd76b9c | 1269 | FAIL; |
c11394f8 OE |
1270 | |
1271 | emit_insn (atomic_insn); | |
7768ec4c | 1272 | |
7768ec4c KK |
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; | |
1280 | }) | |
1281 | ||
3548abca | 1282 | (define_insn_and_split "atomic_fetch_nandsi_hard" |
c761dca1 | 1283 | [(set (match_operand:SI 0 "arith_reg_dest" "=&r") |
2fdc0399 OE |
1284 | (match_operand:SI 1 "atomic_mem_operand_1" "=Sra")) |
1285 | (set (match_dup 1) | |
c11394f8 | 1286 | (unspec:SI |
2fdc0399 | 1287 | [(not:SI (and:SI (match_dup 1) |
c11394f8 OE |
1288 | (match_operand:SI 2 "logical_operand" "rK08")))] |
1289 | UNSPEC_ATOMIC)) | |
659a6a94 | 1290 | (set (reg:SI T_REG) (const_int 1)) |
c11394f8 | 1291 | (clobber (reg:SI R0_REG))] |
7bd76b9c | 1292 | "TARGET_ATOMIC_HARD_LLCS |
f3ca7111 | 1293 | || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" |
c11394f8 | 1294 | { |
2fdc0399 | 1295 | return "\r0: movli.l %1,r0" "\n" |
c11394f8 OE |
1296 | " mov r0,%0" "\n" |
1297 | " and %2,r0" "\n" | |
1298 | " not r0,r0" "\n" | |
2fdc0399 | 1299 | " movco.l r0,%1" "\n" |
c11394f8 | 1300 | " bf 0b"; |
3548abca OE |
1301 | } |
1302 | "&& can_create_pseudo_p () && optimize | |
1303 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
1304 | [(const_int 0)] | |
1305 | { | |
1306 | emit_insn (gen_atomic_nand_fetchsi_hard (gen_reg_rtx (SImode), operands[1], | |
1307 | operands[2])); | |
c11394f8 OE |
1308 | } |
1309 | [(set_attr "length" "12")]) | |
1310 | ||
2fdc0399 OE |
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. | |
3548abca | 1316 | (define_insn_and_split "atomic_fetch_nand<mode>_hard" |
2fdc0399 OE |
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)] | |
1330 | { | |
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]); | |
1338 | ||
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 | } | |
1347 | }) | |
1348 | ||
1349 | (define_insn "atomic_fetch_nand<mode>_hard_1" | |
c761dca1 OE |
1350 | [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r") |
1351 | (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r"))) | |
7fa4bf9b OE |
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")))] | |
c11394f8 | 1356 | UNSPEC_ATOMIC)) |
659a6a94 | 1357 | (set (reg:SI T_REG) (const_int 1)) |
c11394f8 OE |
1358 | (clobber (reg:SI R0_REG)) |
1359 | (clobber (match_scratch:SI 3 "=&r")) | |
1360 | (clobber (match_scratch:SI 4 "=1"))] | |
7bd76b9c | 1361 | "TARGET_ATOMIC_HARD_LLCS" |
c11394f8 OE |
1362 | { |
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" | |
7fa4bf9b | 1370 | " mov.<bw> @%1,r0" "\n" |
c11394f8 OE |
1371 | " mov r0,%0" "\n" |
1372 | " and %2,r0" "\n" | |
1373 | " not r0,r0" "\n" | |
7fa4bf9b | 1374 | " mov.<bw> r0,@%1" "\n" |
c11394f8 OE |
1375 | " mov.l @r15+,r0" "\n" |
1376 | " movco.l r0,@%3" "\n" | |
1377 | " bf 0b"; | |
3548abca | 1378 | } |
2fdc0399 OE |
1379 | [(set_attr "length" "30")]) |
1380 | ||
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" | |
3548abca OE |
1397 | [(const_int 0)] |
1398 | { | |
2fdc0399 OE |
1399 | rtx i = gen_atomic_nand<mode>_hard_1 (XEXP (operands[0], 0), operands[1]); |
1400 | ||
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); | |
1406 | }) | |
c11394f8 | 1407 | |
2fdc0399 | 1408 | (define_insn "atomic_nand<mode>_hard_1" |
3548abca OE |
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" | |
1419 | { | |
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"; | |
1434 | } | |
1435 | [(set_attr "length" "28")]) | |
1436 | ||
1437 | (define_insn_and_split "atomic_fetch_nand<mode>_soft_gusa" | |
c761dca1 | 1438 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u") |
2fdc0399 OE |
1439 | (match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd")) |
1440 | (set (match_dup 1) | |
7fa4bf9b | 1441 | (unspec:QIHISI |
c761dca1 | 1442 | [(not:QIHISI |
2fdc0399 | 1443 | (and:QIHISI (match_dup 1) |
c761dca1 | 1444 | (match_operand:QIHISI 2 "arith_reg_operand" "u")))] |
7768ec4c | 1445 | UNSPEC_ATOMIC)) |
7fa4bf9b | 1446 | (clobber (match_scratch:QIHISI 3 "=&u")) |
7768ec4c KK |
1447 | (clobber (reg:SI R0_REG)) |
1448 | (clobber (reg:SI R1_REG))] | |
7bd76b9c | 1449 | "TARGET_ATOMIC_SOFT_GUSA" |
7768ec4c | 1450 | { |
c11394f8 | 1451 | return "\r mova 1f,r0" "\n" |
f3322315 OE |
1452 | " mov r15,r1" "\n" |
1453 | " .align 2" "\n" | |
1454 | " mov #(0f-1f),r15" "\n" | |
2fdc0399 | 1455 | "0: mov.<bwl> %1,%0" "\n" |
f3322315 OE |
1456 | " mov %2,%3" "\n" |
1457 | " and %0,%3" "\n" | |
1458 | " not %3,%3" "\n" | |
2fdc0399 | 1459 | " mov.<bwl> %3,%1" "\n" |
f3322315 | 1460 | "1: mov r1,r15"; |
3548abca OE |
1461 | } |
1462 | "&& can_create_pseudo_p () && optimize | |
1463 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
1464 | [(const_int 0)] | |
1465 | { | |
1466 | emit_insn (gen_atomic_nand_fetch<mode>_soft_gusa (gen_reg_rtx (<MODE>mode), | |
1467 | operands[1], operands[2])); | |
f3322315 | 1468 | } |
7768ec4c KK |
1469 | [(set_attr "length" "20")]) |
1470 | ||
3548abca | 1471 | (define_insn_and_split "atomic_fetch_nand<mode>_soft_tcb" |
c761dca1 | 1472 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r") |
2fdc0399 OE |
1473 | (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")) |
1474 | (set (match_dup 1) | |
7bd76b9c | 1475 | (unspec:QIHISI |
c761dca1 | 1476 | [(not:QIHISI |
2fdc0399 | 1477 | (and:QIHISI (match_dup 1) |
c761dca1 | 1478 | (match_operand:QIHISI 2 "logical_operand" "rK08")))] |
7bd76b9c OE |
1479 | UNSPEC_ATOMIC)) |
1480 | (use (match_operand:SI 3 "gbr_displacement")) | |
7bd76b9c OE |
1481 | (clobber (reg:SI R0_REG)) |
1482 | (clobber (reg:SI R1_REG))] | |
1483 | "TARGET_ATOMIC_SOFT_TCB" | |
1484 | { | |
1485 | return "\r mova 1f,r0" "\n" | |
7bd76b9c | 1486 | " mov #(0f-1f),r1" "\n" |
c761dca1 | 1487 | " .align 2" "\n" |
7bd76b9c | 1488 | " mov.l r0,@(%O3,gbr)" "\n" |
2fdc0399 | 1489 | "0: mov.<bwl> %1,r0" "\n" |
c761dca1 OE |
1490 | " mov r0,%0" "\n" |
1491 | " and %2,r0" "\n" | |
1492 | " not r0,r0" "\n" | |
2fdc0399 | 1493 | " mov.<bwl> r0,%1" "\n" |
c761dca1 OE |
1494 | "1: mov #0,r0" "\n" |
1495 | " mov.l r0,@(%O3,gbr)"; | |
3548abca OE |
1496 | } |
1497 | "&& can_create_pseudo_p () && optimize | |
1498 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
1499 | [(const_int 0)] | |
1500 | { | |
1501 | emit_insn (gen_atomic_nand<mode>_soft_tcb (operands[1], operands[2], | |
1502 | operands[3])); | |
7bd76b9c OE |
1503 | } |
1504 | [(set_attr "length" "22")]) | |
1505 | ||
3548abca | 1506 | (define_insn "atomic_nand<mode>_soft_tcb" |
2fdc0399 | 1507 | [(set (match_operand:QIHISI 0 "atomic_mem_operand_1" "=SraSdd") |
3548abca OE |
1508 | (unspec:QIHISI |
1509 | [(not:QIHISI | |
2fdc0399 | 1510 | (and:QIHISI (match_dup 0) |
3548abca OE |
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" | |
1517 | { | |
1518 | return "\r mova 1f,r0" "\n" | |
1519 | " .align 2" "\n" | |
1520 | " mov #(0f-1f),r1" "\n" | |
1521 | " mov.l r0,@(%O2,gbr)" "\n" | |
2fdc0399 | 1522 | "0: mov.<bwl> %0,r0" "\n" |
3548abca OE |
1523 | " and %1,r0" "\n" |
1524 | " not r0,r0" "\n" | |
2fdc0399 | 1525 | " mov.<bwl> r0,%0" "\n" |
3548abca OE |
1526 | "1: mov #0,r0" "\n" |
1527 | " mov.l r0,@(%O2,gbr)"; | |
1528 | } | |
1529 | [(set_attr "length" "20")]) | |
1530 | ||
1531 | (define_insn_and_split "atomic_fetch_nand<mode>_soft_imask" | |
c761dca1 | 1532 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r") |
2fdc0399 OE |
1533 | (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd")) |
1534 | (set (match_dup 1) | |
7bd76b9c | 1535 | (unspec:QIHISI |
c761dca1 | 1536 | [(not:QIHISI |
2fdc0399 | 1537 | (and:QIHISI (match_dup 1) |
c761dca1 | 1538 | (match_operand:QIHISI 2 "logical_operand" "rK08")))] |
7bd76b9c | 1539 | UNSPEC_ATOMIC)) |
c761dca1 OE |
1540 | (clobber (reg:SI R0_REG)) |
1541 | (clobber (match_scratch:SI 3 "=&r"))] | |
7bd76b9c OE |
1542 | "TARGET_ATOMIC_SOFT_IMASK" |
1543 | { | |
c761dca1 OE |
1544 | return "\r stc sr,r0" "\n" |
1545 | " mov r0,%3" "\n" | |
1546 | " or #0xF0,r0" "\n" | |
1547 | " ldc r0,sr" "\n" | |
2fdc0399 | 1548 | " mov.<bwl> %1,r0" "\n" |
c761dca1 OE |
1549 | " mov r0,%0" "\n" |
1550 | " and %2,r0" "\n" | |
1551 | " not r0,r0" "\n" | |
2fdc0399 | 1552 | " mov.<bwl> r0,%1" "\n" |
c761dca1 | 1553 | " ldc %3,sr"; |
3548abca OE |
1554 | } |
1555 | "&& can_create_pseudo_p () && optimize | |
1556 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
1557 | [(const_int 0)] | |
1558 | { | |
1559 | emit_insn (gen_atomic_nand_fetch<mode>_soft_imask (gen_reg_rtx (<MODE>mode), | |
1560 | operands[1], operands[2])); | |
7bd76b9c OE |
1561 | } |
1562 | [(set_attr "length" "20")]) | |
1563 | ||
c11394f8 OE |
1564 | ;;------------------------------------------------------------------------------ |
1565 | ;; read - add|sub|or|and|xor|nand - write - return new value | |
1566 | ||
7768ec4c | 1567 | (define_expand "atomic_<fetchop_name>_fetch<mode>" |
c761dca1 | 1568 | [(set (match_operand:QIHISI 0 "arith_reg_dest") |
7fa4bf9b | 1569 | (FETCHOP:QIHISI |
2fdc0399 | 1570 | (match_operand:QIHISI 1 "atomic_mem_operand_1") |
c761dca1 | 1571 | (match_operand:QIHISI 2 "<fetchop_predicate_1>"))) |
7768ec4c | 1572 | (set (match_dup 1) |
7fa4bf9b OE |
1573 | (unspec:QIHISI |
1574 | [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))] | |
7768ec4c KK |
1575 | UNSPEC_ATOMIC)) |
1576 | (match_operand:SI 3 "const_int_operand" "")] | |
7bd76b9c | 1577 | "TARGET_ATOMIC_ANY" |
7768ec4c | 1578 | { |
2fdc0399 | 1579 | rtx mem = operands[1]; |
c11394f8 OE |
1580 | rtx atomic_insn; |
1581 | ||
7bd76b9c | 1582 | if (TARGET_ATOMIC_HARD_LLCS |
f3ca7111 | 1583 | || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) |
2fdc0399 | 1584 | atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_hard (operands[0], mem, |
c11394f8 | 1585 | operands[2]); |
7bd76b9c OE |
1586 | else if (TARGET_ATOMIC_SOFT_GUSA) |
1587 | atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_gusa (operands[0], | |
2fdc0399 | 1588 | mem, operands[2]); |
7bd76b9c OE |
1589 | else if (TARGET_ATOMIC_SOFT_TCB) |
1590 | atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_tcb (operands[0], | |
2fdc0399 | 1591 | mem, operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX); |
7bd76b9c OE |
1592 | else if (TARGET_ATOMIC_SOFT_IMASK) |
1593 | atomic_insn = gen_atomic_<fetchop_name>_fetch<mode>_soft_imask (operands[0], | |
2fdc0399 | 1594 | mem, operands[2]); |
c11394f8 | 1595 | else |
7bd76b9c OE |
1596 | FAIL; |
1597 | ||
c11394f8 | 1598 | emit_insn (atomic_insn); |
7768ec4c | 1599 | |
7768ec4c KK |
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; | |
1607 | }) | |
1608 | ||
c11394f8 | 1609 | (define_insn "atomic_<fetchop_name>_fetchsi_hard" |
c761dca1 | 1610 | [(set (match_operand:SI 0 "arith_reg_dest" "=&z") |
c11394f8 | 1611 | (FETCHOP:SI |
2fdc0399 | 1612 | (match_operand:SI 1 "atomic_mem_operand_1" "=Sra") |
c761dca1 OE |
1613 | (match_operand:SI 2 "<fetchop_predicate_1>" |
1614 | "<fetchop_constraint_1_llcs>"))) | |
2fdc0399 | 1615 | (set (match_dup 1) |
c11394f8 | 1616 | (unspec:SI |
2fdc0399 | 1617 | [(FETCHOP:SI (match_dup 1) (match_dup 2))] |
659a6a94 OE |
1618 | UNSPEC_ATOMIC)) |
1619 | (set (reg:SI T_REG) (const_int 1))] | |
7bd76b9c | 1620 | "TARGET_ATOMIC_HARD_LLCS |
f3ca7111 | 1621 | || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" |
c11394f8 | 1622 | { |
2fdc0399 | 1623 | return "\r0: movli.l %1,%0" "\n" |
c11394f8 | 1624 | " <fetchop_name> %2,%0" "\n" |
2fdc0399 | 1625 | " movco.l %0,%1" "\n" |
c11394f8 OE |
1626 | " bf 0b"; |
1627 | } | |
1628 | [(set_attr "length" "8")]) | |
1629 | ||
2b8427ca OE |
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") | |
2fdc0399 OE |
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)) | |
2b8427ca OE |
1636 | (set (reg:SI T_REG) (const_int 1))] |
1637 | "TARGET_ATOMIC_HARD_LLCS | |
1638 | || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" | |
1639 | { | |
2fdc0399 | 1640 | return "\r0: movli.l %1,%0" "\n" |
2b8427ca | 1641 | " not %0,%0" "\n" |
2fdc0399 | 1642 | " movco.l %0,%1" "\n" |
2b8427ca OE |
1643 | " bf 0b"; |
1644 | } | |
1645 | [(set_attr "length" "8")]) | |
1646 | ||
2fdc0399 OE |
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. | |
3548abca | 1652 | (define_insn_and_split "atomic_<fetchop_name>_fetch<mode>_hard" |
2fdc0399 OE |
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)] | |
1664 | { | |
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]); | |
1672 | ||
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 | } | |
1680 | }) | |
1681 | ||
1682 | (define_insn "atomic_<fetchop_name>_fetch<mode>_hard_1" | |
c761dca1 | 1683 | [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r") |
7fa4bf9b | 1684 | (FETCHOP:QIHI |
c761dca1 OE |
1685 | (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")) |
1686 | (match_operand:QIHI 2 "<fetchop_predicate_1>" | |
1687 | "<fetchop_constraint_1_llcs>"))) | |
7fa4bf9b OE |
1688 | (set (mem:QIHI (match_dup 1)) |
1689 | (unspec:QIHI | |
1690 | [(FETCHOP:QIHI (mem:QIHI (match_dup 1)) (match_dup 2))] | |
c11394f8 | 1691 | UNSPEC_ATOMIC)) |
659a6a94 | 1692 | (set (reg:SI T_REG) (const_int 1)) |
c11394f8 OE |
1693 | (clobber (reg:SI R0_REG)) |
1694 | (clobber (match_scratch:SI 3 "=&r")) | |
1695 | (clobber (match_scratch:SI 4 "=1"))] | |
7bd76b9c | 1696 | "TARGET_ATOMIC_HARD_LLCS" |
c11394f8 OE |
1697 | { |
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" | |
7fa4bf9b | 1705 | " mov.<bw> @%1,r0" "\n" |
c11394f8 | 1706 | " <fetchop_name> %2,r0" "\n" |
7fa4bf9b | 1707 | " mov.<bw> r0,@%1" "\n" |
c11394f8 OE |
1708 | " mov r0,%0" "\n" |
1709 | " mov.l @r15+,r0" "\n" | |
1710 | " movco.l r0,@%3" "\n" | |
1711 | " bf 0b"; | |
1712 | } | |
1713 | [(set_attr "length" "28")]) | |
1714 | ||
2b8427ca | 1715 | ;; Combine pattern for xor (val, -1) / nand (val, -1). |
3548abca | 1716 | (define_insn_and_split "atomic_not_fetch<mode>_hard" |
2b8427ca OE |
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" | |
1726 | { | |
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"; | |
3548abca OE |
1741 | } |
1742 | "&& can_create_pseudo_p () && optimize | |
1743 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
1744 | [(const_int 0)] | |
1745 | { | |
2fdc0399 OE |
1746 | rtx i = gen_atomic_not<mode>_hard (operands[1]); |
1747 | ||
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); | |
2b8427ca OE |
1754 | } |
1755 | [(set_attr "length" "28")]) | |
1756 | ||
7bd76b9c | 1757 | (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_gusa" |
c761dca1 | 1758 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u") |
7fa4bf9b | 1759 | (FETCHOP:QIHISI |
2fdc0399 | 1760 | (match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd") |
c761dca1 OE |
1761 | (match_operand:QIHISI 2 "<fetchop_predicate_1>" |
1762 | "<fetchop_constraint_1_gusa>"))) | |
2fdc0399 | 1763 | (set (match_dup 1) |
7fa4bf9b | 1764 | (unspec:QIHISI |
2fdc0399 | 1765 | [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))] |
7768ec4c KK |
1766 | UNSPEC_ATOMIC)) |
1767 | (clobber (reg:SI R0_REG)) | |
1768 | (clobber (reg:SI R1_REG))] | |
7bd76b9c | 1769 | "TARGET_ATOMIC_SOFT_GUSA" |
7768ec4c | 1770 | { |
c11394f8 | 1771 | return "\r mova 1f,r0" "\n" |
f3322315 OE |
1772 | " mov r15,r1" "\n" |
1773 | " .align 2" "\n" | |
1774 | " mov #(0f-1f),r15" "\n" | |
2fdc0399 | 1775 | "0: mov.<bwl> %1,%0" "\n" |
f3322315 | 1776 | " <fetchop_name> %2,%0" "\n" |
2fdc0399 | 1777 | " mov.<bwl> %0,%1" "\n" |
f3322315 OE |
1778 | "1: mov r1,r15"; |
1779 | } | |
7768ec4c KK |
1780 | [(set_attr "length" "16")]) |
1781 | ||
2b8427ca OE |
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") | |
2fdc0399 OE |
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)) | |
2b8427ca OE |
1788 | (clobber (reg:SI R0_REG)) |
1789 | (clobber (reg:SI R1_REG))] | |
1790 | "TARGET_ATOMIC_SOFT_GUSA" | |
1791 | { | |
1792 | return "\r mova 1f,r0" "\n" | |
1793 | " mov r15,r1" "\n" | |
1794 | " .align 2" "\n" | |
1795 | " mov #(0f-1f),r15" "\n" | |
2fdc0399 OE |
1796 | "0: mov.<bwl> %1,%0" "\n" |
1797 | " not %0,%0" "\n" | |
1798 | " mov.<bwl> %0,%1" "\n" | |
2b8427ca OE |
1799 | "1: mov r1,r15"; |
1800 | } | |
1801 | [(set_attr "length" "16")]) | |
1802 | ||
3548abca | 1803 | (define_insn_and_split "atomic_<fetchop_name>_fetch<mode>_soft_tcb" |
c761dca1 | 1804 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r") |
7bd76b9c | 1805 | (FETCHOP:QIHISI |
2fdc0399 | 1806 | (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd") |
c761dca1 OE |
1807 | (match_operand:QIHISI 2 "<fetchop_predicate_1>" |
1808 | "<fetchop_constraint_1_tcb>"))) | |
2fdc0399 | 1809 | (set (match_dup 1) |
7bd76b9c | 1810 | (unspec:QIHISI |
2fdc0399 | 1811 | [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))] |
7bd76b9c OE |
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" | |
1817 | { | |
1818 | return "\r mova 1f,r0" "\n" | |
7bd76b9c | 1819 | " mov #(0f-1f),r1" "\n" |
c761dca1 | 1820 | " .align 2" "\n" |
7bd76b9c | 1821 | " mov.l r0,@(%O3,gbr)" "\n" |
2fdc0399 | 1822 | "0: mov.<bwl> %1,r0" "\n" |
c761dca1 | 1823 | " <fetchop_name> %2,r0" "\n" |
2fdc0399 | 1824 | " mov.<bwl> r0,%1" "\n" |
c761dca1 | 1825 | "1: mov r0,%0" "\n" |
7bd76b9c | 1826 | " mov #0,r0" "\n" |
c761dca1 | 1827 | " mov.l r0,@(%O3,gbr)"; |
3548abca OE |
1828 | } |
1829 | "&& can_create_pseudo_p () && optimize | |
1830 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
1831 | [(const_int 0)] | |
1832 | { | |
1833 | emit_insn (gen_atomic_<fetchop_name><mode>_soft_tcb ( | |
1834 | operands[1], operands[2], operands[3])); | |
7bd76b9c | 1835 | } |
c761dca1 | 1836 | [(set_attr "length" "20")]) |
7bd76b9c | 1837 | |
2b8427ca | 1838 | ;; Combine pattern for xor (val, -1) / nand (val, -1). |
3548abca | 1839 | (define_insn_and_split "atomic_not_fetch<mode>_soft_tcb" |
2b8427ca | 1840 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r") |
2fdc0399 OE |
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)) | |
2b8427ca OE |
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" | |
1848 | { | |
1849 | return "\r mova 1f,r0" "\n" | |
1850 | " mov #(0f-1f),r1" "\n" | |
1851 | " .align 2" "\n" | |
1852 | " mov.l r0,@(%O2,gbr)" "\n" | |
2fdc0399 OE |
1853 | "0: mov.<bwl> %1,r0" "\n" |
1854 | " not r0,r0" "\n" | |
1855 | " mov.<bwl> r0,%1" "\n" | |
2b8427ca OE |
1856 | "1: mov r0,%0" "\n" |
1857 | " mov #0,r0" "\n" | |
1858 | " mov.l r0,@(%O2,gbr)"; | |
3548abca OE |
1859 | } |
1860 | "&& can_create_pseudo_p () && optimize | |
1861 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
1862 | [(const_int 0)] | |
1863 | { | |
1864 | emit_insn (gen_atomic_not<mode>_soft_tcb (operands[1], operands[2])); | |
2b8427ca OE |
1865 | } |
1866 | [(set_attr "length" "20")]) | |
1867 | ||
7bd76b9c | 1868 | (define_insn "atomic_<fetchop_name>_fetch<mode>_soft_imask" |
c761dca1 | 1869 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z") |
7bd76b9c | 1870 | (FETCHOP:QIHISI |
2fdc0399 | 1871 | (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd") |
c761dca1 OE |
1872 | (match_operand:QIHISI 2 "<fetchop_predicate_1>" |
1873 | "<fetchop_constraint_1_imask>"))) | |
2fdc0399 | 1874 | (set (match_dup 1) |
7bd76b9c | 1875 | (unspec:QIHISI |
2fdc0399 | 1876 | [(FETCHOP:QIHISI (match_dup 1) (match_dup 2))] |
7bd76b9c OE |
1877 | UNSPEC_ATOMIC)) |
1878 | (clobber (match_scratch:SI 3 "=&r"))] | |
1879 | "TARGET_ATOMIC_SOFT_IMASK" | |
1880 | { | |
1881 | return "\r stc sr,%0" "\n" | |
1882 | " mov %0,%3" "\n" | |
1883 | " or #0xF0,%0" "\n" | |
1884 | " ldc %0,sr" "\n" | |
2fdc0399 | 1885 | " mov.<bwl> %1,%0" "\n" |
7bd76b9c | 1886 | " <fetchop_name> %2,%0" "\n" |
2fdc0399 | 1887 | " mov.<bwl> %0,%1" "\n" |
7bd76b9c OE |
1888 | " ldc %3,sr"; |
1889 | } | |
1890 | [(set_attr "length" "16")]) | |
1891 | ||
2b8427ca OE |
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") | |
2fdc0399 OE |
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)) | |
2b8427ca OE |
1898 | (clobber (match_scratch:SI 2 "=&r"))] |
1899 | "TARGET_ATOMIC_SOFT_IMASK" | |
1900 | { | |
1901 | return "\r stc sr,%0" "\n" | |
1902 | " mov %0,%2" "\n" | |
1903 | " or #0xF0,%0" "\n" | |
1904 | " ldc %0,sr" "\n" | |
2fdc0399 OE |
1905 | " mov.<bwl> %1,%0" "\n" |
1906 | " not %0,%0" "\n" | |
1907 | " mov.<bwl> %0,%1" "\n" | |
2b8427ca OE |
1908 | " ldc %2,sr"; |
1909 | } | |
1910 | [(set_attr "length" "16")]) | |
1911 | ||
7768ec4c | 1912 | (define_expand "atomic_nand_fetch<mode>" |
c761dca1 | 1913 | [(set (match_operand:QIHISI 0 "arith_reg_dest") |
7fa4bf9b | 1914 | (not:QIHISI (and:QIHISI |
2fdc0399 | 1915 | (match_operand:QIHISI 1 "atomic_mem_operand_1") |
c761dca1 | 1916 | (match_operand:QIHISI 2 "atomic_logical_operand_1")))) |
7768ec4c | 1917 | (set (match_dup 1) |
7fa4bf9b OE |
1918 | (unspec:QIHISI |
1919 | [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))] | |
7768ec4c | 1920 | UNSPEC_ATOMIC)) |
c761dca1 | 1921 | (match_operand:SI 3 "const_int_operand")] |
7bd76b9c | 1922 | "TARGET_ATOMIC_ANY" |
7768ec4c | 1923 | { |
2fdc0399 | 1924 | rtx mem = operands[1]; |
c11394f8 OE |
1925 | rtx atomic_insn; |
1926 | ||
7bd76b9c | 1927 | if (TARGET_ATOMIC_HARD_LLCS |
f3ca7111 | 1928 | || (TARGET_SH4A && <MODE>mode == SImode && !TARGET_ATOMIC_STRICT)) |
2fdc0399 | 1929 | atomic_insn = gen_atomic_nand_fetch<mode>_hard (operands[0], mem, |
c11394f8 | 1930 | operands[2]); |
7bd76b9c | 1931 | else if (TARGET_ATOMIC_SOFT_GUSA) |
2fdc0399 | 1932 | atomic_insn = gen_atomic_nand_fetch<mode>_soft_gusa (operands[0], mem, |
7bd76b9c OE |
1933 | operands[2]); |
1934 | else if (TARGET_ATOMIC_SOFT_TCB) | |
2fdc0399 | 1935 | atomic_insn = gen_atomic_nand_fetch<mode>_soft_tcb (operands[0], mem, |
7bd76b9c OE |
1936 | operands[2], TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX); |
1937 | else if (TARGET_ATOMIC_SOFT_IMASK) | |
2fdc0399 | 1938 | atomic_insn = gen_atomic_nand_fetch<mode>_soft_imask (operands[0], mem, |
7bd76b9c | 1939 | operands[2]); |
c11394f8 | 1940 | else |
7bd76b9c OE |
1941 | FAIL; |
1942 | ||
c11394f8 | 1943 | emit_insn (atomic_insn); |
7768ec4c | 1944 | |
7768ec4c KK |
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; | |
1952 | }) | |
1953 | ||
c11394f8 | 1954 | (define_insn "atomic_nand_fetchsi_hard" |
c761dca1 | 1955 | [(set (match_operand:SI 0 "arith_reg_dest" "=&z") |
2fdc0399 | 1956 | (not:SI (and:SI (match_operand:SI 1 "atomic_mem_operand_1" "=Sra") |
c11394f8 | 1957 | (match_operand:SI 2 "logical_operand" "rK08")))) |
2fdc0399 | 1958 | (set (match_dup 1) |
c11394f8 | 1959 | (unspec:SI |
2fdc0399 | 1960 | [(not:SI (and:SI (match_dup 1) (match_dup 2)))] |
659a6a94 OE |
1961 | UNSPEC_ATOMIC)) |
1962 | (set (reg:SI T_REG) (const_int 1))] | |
7bd76b9c | 1963 | "TARGET_ATOMIC_HARD_LLCS |
f3ca7111 | 1964 | || (TARGET_SH4A && TARGET_ATOMIC_ANY && !TARGET_ATOMIC_STRICT)" |
c11394f8 | 1965 | { |
2fdc0399 | 1966 | return "\r0: movli.l %1,%0" "\n" |
c11394f8 OE |
1967 | " and %2,%0" "\n" |
1968 | " not %0,%0" "\n" | |
2fdc0399 | 1969 | " movco.l %0,%1" "\n" |
c11394f8 OE |
1970 | " bf 0b"; |
1971 | } | |
1972 | [(set_attr "length" "10")]) | |
1973 | ||
2fdc0399 OE |
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. | |
3548abca | 1979 | (define_insn_and_split "atomic_nand_fetch<mode>_hard" |
2fdc0399 OE |
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)] | |
1992 | { | |
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 | } | |
2009 | }) | |
2010 | ||
2011 | (define_insn "atomic_nand_fetch<mode>_hard_1" | |
c761dca1 | 2012 | [(set (match_operand:QIHI 0 "arith_reg_dest" "=&r") |
7fa4bf9b | 2013 | (not:QIHI |
c761dca1 | 2014 | (and:QIHI (mem:QIHI (match_operand:SI 1 "arith_reg_operand" "r")) |
7fa4bf9b OE |
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)))] | |
c11394f8 | 2019 | UNSPEC_ATOMIC)) |
659a6a94 | 2020 | (set (reg:SI T_REG) (const_int 1)) |
c11394f8 OE |
2021 | (clobber (reg:SI R0_REG)) |
2022 | (clobber (match_scratch:SI 3 "=&r")) | |
2023 | (clobber (match_scratch:SI 4 "=1"))] | |
7bd76b9c | 2024 | "TARGET_ATOMIC_HARD_LLCS" |
c11394f8 OE |
2025 | { |
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" | |
7fa4bf9b | 2033 | " mov.<bw> @%1,r0" "\n" |
c11394f8 OE |
2034 | " and %2,r0" "\n" |
2035 | " not r0,%0" "\n" | |
7fa4bf9b | 2036 | " mov.<bw> %0,@%1" "\n" |
c11394f8 OE |
2037 | " mov.l @r15+,r0" "\n" |
2038 | " movco.l r0,@%3" "\n" | |
2039 | " bf 0b"; | |
2040 | } | |
2041 | [(set_attr "length" "28")]) | |
2042 | ||
7bd76b9c | 2043 | (define_insn "atomic_nand_fetch<mode>_soft_gusa" |
c761dca1 | 2044 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&u") |
7fa4bf9b | 2045 | (not:QIHISI (and:QIHISI |
2fdc0399 | 2046 | (match_operand:QIHISI 1 "atomic_mem_operand_1" "=AraAdd") |
c761dca1 | 2047 | (match_operand:QIHISI 2 "arith_reg_operand" "u")))) |
2fdc0399 | 2048 | (set (match_dup 1) |
7fa4bf9b | 2049 | (unspec:QIHISI |
2fdc0399 | 2050 | [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))] |
7768ec4c KK |
2051 | UNSPEC_ATOMIC)) |
2052 | (clobber (reg:SI R0_REG)) | |
2053 | (clobber (reg:SI R1_REG))] | |
7bd76b9c | 2054 | "TARGET_ATOMIC_SOFT_GUSA" |
7768ec4c | 2055 | { |
c11394f8 | 2056 | return "\r mova 1f,r0" "\n" |
f3322315 OE |
2057 | " .align 2" "\n" |
2058 | " mov r15,r1" "\n" | |
2059 | " mov #(0f-1f),r15" "\n" | |
2fdc0399 | 2060 | "0: mov.<bwl> %1,%0" "\n" |
f3322315 OE |
2061 | " and %2,%0" "\n" |
2062 | " not %0,%0" "\n" | |
2fdc0399 | 2063 | " mov.<bwl> %0,%1" "\n" |
f3322315 OE |
2064 | "1: mov r1,r15"; |
2065 | } | |
7768ec4c | 2066 | [(set_attr "length" "18")]) |
ab649754 | 2067 | |
3548abca | 2068 | (define_insn_and_split "atomic_nand_fetch<mode>_soft_tcb" |
c761dca1 | 2069 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&r") |
7bd76b9c | 2070 | (not:QIHISI (and:QIHISI |
2fdc0399 | 2071 | (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd") |
c761dca1 | 2072 | (match_operand:QIHISI 2 "logical_operand" "rK08")))) |
2fdc0399 | 2073 | (set (match_dup 1) |
7bd76b9c | 2074 | (unspec:QIHISI |
2fdc0399 | 2075 | [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))] |
7bd76b9c OE |
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" | |
2081 | { | |
2082 | return "\r mova 1f,r0" "\n" | |
2083 | " mov #(0f-1f),r1" "\n" | |
2084 | " .align 2" "\n" | |
2085 | " mov.l r0,@(%O3,gbr)" "\n" | |
2fdc0399 | 2086 | "0: mov.<bwl> %1,r0" "\n" |
c761dca1 OE |
2087 | " and %2,r0" "\n" |
2088 | " not r0,r0" "\n" | |
2089 | " mov r0,%0" "\n" | |
2fdc0399 | 2090 | " mov.<bwl> r0,%1" "\n" |
c761dca1 OE |
2091 | "1: mov #0,r0" "\n" |
2092 | " mov.l r0,@(%O3,gbr)"; | |
3548abca OE |
2093 | } |
2094 | "&& can_create_pseudo_p () && optimize | |
2095 | && sh_reg_dead_or_unused_after_insn (insn, REGNO (operands[0]))" | |
2096 | [(const_int 0)] | |
2097 | { | |
2098 | emit_insn (gen_atomic_nand<mode>_soft_tcb (operands[1], operands[2], | |
2099 | operands[3])); | |
7bd76b9c | 2100 | } |
c761dca1 | 2101 | [(set_attr "length" "22")]) |
7bd76b9c OE |
2102 | |
2103 | (define_insn "atomic_nand_fetch<mode>_soft_imask" | |
c761dca1 | 2104 | [(set (match_operand:QIHISI 0 "arith_reg_dest" "=&z") |
7bd76b9c | 2105 | (not:QIHISI (and:QIHISI |
2fdc0399 | 2106 | (match_operand:QIHISI 1 "atomic_mem_operand_1" "=SraSdd") |
c761dca1 | 2107 | (match_operand:QIHISI 2 "logical_operand" "rK08")))) |
2fdc0399 | 2108 | (set (match_dup 1) |
7bd76b9c | 2109 | (unspec:QIHISI |
2fdc0399 | 2110 | [(not:QIHISI (and:QIHISI (match_dup 1) (match_dup 2)))] |
7bd76b9c OE |
2111 | UNSPEC_ATOMIC)) |
2112 | (clobber (match_scratch:SI 3 "=&r"))] | |
2113 | "TARGET_ATOMIC_SOFT_IMASK" | |
2114 | { | |
2115 | return "\r stc sr,%0" "\n" | |
2116 | " mov %0,%3" "\n" | |
2117 | " or #0xF0,%0" "\n" | |
2118 | " ldc %0,sr" "\n" | |
2fdc0399 | 2119 | " mov.<bwl> %1,%0" "\n" |
7bd76b9c OE |
2120 | " and %2,%0" "\n" |
2121 | " not %0,%0" "\n" | |
2fdc0399 | 2122 | " mov.<bwl> %0,%1" "\n" |
7bd76b9c OE |
2123 | " ldc %3,sr"; |
2124 | } | |
2125 | [(set_attr "length" "18")]) | |
2126 | ||
c11394f8 OE |
2127 | ;;------------------------------------------------------------------------------ |
2128 | ;; read - test against zero - or with 0x80 - write - return test result | |
2129 | ||
ab649754 OE |
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 | |
e1fab8ba | 2134 | "TARGET_ATOMIC_ANY || TARGET_ENABLE_TAS" |
ab649754 OE |
2135 | { |
2136 | rtx addr = force_reg (Pmode, XEXP (operands[1], 0)); | |
2137 | ||
2138 | if (TARGET_ENABLE_TAS) | |
2139 | emit_insn (gen_tasb (addr)); | |
2140 | else | |
2141 | { | |
c11394f8 | 2142 | rtx val = gen_int_mode (targetm.atomic_test_and_set_trueval, QImode); |
3b1552c1 | 2143 | val = force_reg (QImode, val); |
c11394f8 | 2144 | |
7bd76b9c | 2145 | if (TARGET_ATOMIC_HARD_LLCS) |
c11394f8 | 2146 | emit_insn (gen_atomic_test_and_set_hard (addr, val)); |
7bd76b9c OE |
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)); | |
c11394f8 | 2154 | else |
7bd76b9c | 2155 | FAIL; |
ab649754 OE |
2156 | } |
2157 | ||
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. */ | |
78ff60c1 | 2161 | emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ())); |
ab649754 OE |
2162 | DONE; |
2163 | }) | |
2164 | ||
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))] | |
e1fab8ba | 2171 | "TARGET_ENABLE_TAS" |
ab649754 OE |
2172 | "tas.b @%0" |
2173 | [(set_attr "insn_class" "co_group")]) | |
2174 | ||
7bd76b9c | 2175 | (define_insn "atomic_test_and_set_soft_gusa" |
ab649754 OE |
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))] | |
7bd76b9c | 2184 | "TARGET_ATOMIC_SOFT_GUSA && !TARGET_ENABLE_TAS" |
ab649754 | 2185 | { |
c11394f8 | 2186 | return "\r mova 1f,r0" "\n" |
ab649754 OE |
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"; | |
2194 | } | |
2195 | [(set_attr "length" "16")]) | |
2196 | ||
7bd76b9c OE |
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" | |
2208 | { | |
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"; | |
2218 | } | |
2219 | [(set_attr "length" "18")]) | |
2220 | ||
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" | |
2230 | { | |
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" | |
ad19968e | 2237 | " ldc %2,sr" "\n" |
7bd76b9c OE |
2238 | " tst r0,r0"; |
2239 | } | |
2240 | [(set_attr "length" "16")]) | |
2241 | ||
c11394f8 OE |
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"))] | |
7bd76b9c | 2252 | "TARGET_ATOMIC_HARD_LLCS && !TARGET_ENABLE_TAS" |
c11394f8 OE |
2253 | { |
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"; | |
2267 | } | |
2268 | [(set_attr "length" "26")]) | |
2269 |