113288c7629530174e28ff6c2e3cdec954040759
[gcc.git] / gcc / config / sh / sync.md
1 ;; GCC machine description for SH synchronization instructions.
2 ;; Copyright (C) 2011, 2012
3 ;; Free Software Foundation, Inc.
4 ;;
5 ;; This file is part of GCC.
6 ;;
7 ;; GCC is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation; either version 3, or (at your option)
10 ;; any later version.
11 ;;
12 ;; GCC is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
16 ;;
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GCC; see the file COPYING3. If not see
19 ;; <http://www.gnu.org/licenses/>.
20 ;;
21 ;;
22 ;; Atomic integer operations for the Renesas / SuperH SH CPUs.
23 ;;
24 ;; On single-core systems there can only be one execution context running
25 ;; at a given point in time. This allows the usage of rewindable atomic
26 ;; sequences, which effectively emulate locked-load / conditional-store
27 ;; operations.
28 ;; When an execution context is interrupted while it is an atomic
29 ;; sequence, the interrupted context's PC is rewound to the beginning of
30 ;; the atomic sequence by the interrupt / exception handling code, before
31 ;; transferring control to another execution context. This is done by
32 ;; something like...
33 ;;
34 ;; if (interrupted_context_in_atomic_sequence
35 ;; && interrupted_pc < atomic_exitpoint)
36 ;; interrupted_pc = atomic_entrypoint;
37 ;;
38 ;; This method is also known as gUSA ("g" User Space Atomicity) and the
39 ;; Linux kernel for SH3/SH4 implements support for such software
40 ;; atomic sequences. However, it can also be implemented in freestanding
41 ;; environments.
42 ;;
43 ;; For this the following atomic sequence ABI is used.
44 ;;
45 ;; r15 >= 0: Execution context is not in an atomic sequence.
46 ;;
47 ;; r15 < 0: Execution context is in an atomic sequence and r15
48 ;; holds the negative byte length of the atomic sequence.
49 ;; In this case the following applies:
50 ;;
51 ;; r0: PC of the first instruction after the atomic
52 ;; write-back instruction (exit point).
53 ;; The entry point PC of the atomic sequence can be
54 ;; determined by doing r0 + r15.
55 ;;
56 ;; r1: Saved r15 stack pointer before entering the
57 ;; atomic sequence.
58 ;;
59 ;; An example atomic add sequence would look like:
60 ;;
61 ;; mova .Lend,r0 ! .Lend must be 4-byte aligned.
62 ;; mov r15,r1
63 ;; .align 2 ! Insert aligning nop if needed.
64 ;; mov #(.Lstart - .Lend),r15 ! Enter atomic sequence
65 ;;.Lstart:
66 ;; mov.l @r4,r2 ! read value
67 ;; add r2,r5 ! modify value
68 ;; mov.l r5,@r4 ! write-back
69 ;;.Lend:
70 ;; mov r1,r15 ! Exit atomic sequence
71 ;; ! r2 holds the previous value.
72 ;; ! r5 holds the new value.
73 ;;
74 ;; Notice that due to the restrictions of the mova instruction, the .Lend
75 ;; label must always be 4-byte aligned. Aligning the .Lend label would
76 ;; potentially insert a nop after the write-back instruction which could
77 ;; make the sequence to be rewound, although it has already passed the
78 ;; write-back instruction. This would make it execute twice.
79 ;; For correct operation the atomic sequences must not be rewound after
80 ;; they have passed the write-back instruction.
81 ;;
82 ;; The current implementation is limited to QImode, HImode and SImode
83 ;; atomic operations. DImode operations could also be implemented but
84 ;; would require some ABI modifications to support multiple-instruction
85 ;; write-back. This is because SH1/SH2/SH3/SH4 does not have a DImode
86 ;; store instruction. DImode stores must be split into two SImode stores.
87 ;;
88 ;; For some operations it would be possible to use insns with an immediate
89 ;; operand such as add #imm,Rn. However, since the original value before
90 ;; the operation also needs to be available, this is not so handy.
91
92 (define_c_enum "unspec" [
93 UNSPEC_ATOMIC
94 ])
95
96 (define_c_enum "unspecv" [
97 UNSPECV_CMPXCHG_1
98 UNSPECV_CMPXCHG_2
99 UNSPECV_CMPXCHG_3
100 ])
101
102 (define_mode_iterator I124 [QI HI SI])
103
104 (define_mode_attr i124suffix [(QI "b") (HI "w") (SI "l")])
105 (define_mode_attr i124extend_insn [(QI "exts.b") (HI "exts.w") (SI "mov")])
106
107 (define_code_iterator FETCHOP [plus minus ior xor and])
108 (define_code_attr fetchop_name
109 [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")])
110
111 (define_expand "atomic_compare_and_swap<mode>"
112 [(match_operand:SI 0 "register_operand" "") ;; bool success output
113 (match_operand:I124 1 "register_operand" "") ;; oldval output
114 (match_operand:I124 2 "memory_operand" "") ;; memory
115 (match_operand:I124 3 "register_operand" "") ;; expected input
116 (match_operand:I124 4 "register_operand" "") ;; newval input
117 (match_operand:SI 5 "const_int_operand" "") ;; is_weak
118 (match_operand:SI 6 "const_int_operand" "") ;; success model
119 (match_operand:SI 7 "const_int_operand" "")] ;; failure model
120 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
121 {
122 rtx addr;
123
124 addr = force_reg (Pmode, XEXP (operands[2], 0));
125 emit_insn (gen_atomic_compare_and_swap<mode>_soft
126 (gen_lowpart (SImode, operands[1]), addr, operands[3],
127 operands[4]));
128 if (<MODE>mode == QImode)
129 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[1]),
130 operands[1]));
131 else if (<MODE>mode == HImode)
132 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[1]),
133 operands[1]));
134 emit_insn (gen_movsi (operands[0], gen_rtx_REG (SImode, T_REG)));
135 DONE;
136 })
137
138 (define_insn "atomic_compare_and_swap<mode>_soft"
139 [(set (match_operand:SI 0 "register_operand" "=&u")
140 (unspec_volatile:SI
141 [(mem:I124 (match_operand:SI 1 "register_operand" "u"))
142 (match_operand:I124 2 "register_operand" "u")
143 (match_operand:I124 3 "register_operand" "u")]
144 UNSPECV_CMPXCHG_1))
145 (set (mem:I124 (match_dup 1))
146 (unspec_volatile:I124 [(const_int 0)] UNSPECV_CMPXCHG_2))
147 (set (reg:SI T_REG)
148 (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_3))
149 (clobber (match_scratch:SI 4 "=&u"))
150 (clobber (reg:SI R0_REG))
151 (clobber (reg:SI R1_REG))]
152 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
153 {
154 return "mova 1f,r0" "\n"
155 " <i124extend_insn> %2,%4" "\n"
156 " .align 2" "\n"
157 " mov r15,r1" "\n"
158 " mov #(0f-1f),r15" "\n"
159 "0: mov.<i124suffix> @%1,%0" "\n"
160 " cmp/eq %0,%4" "\n"
161 " bf 1f" "\n"
162 " mov.<i124suffix> %3,@%1" "\n"
163 "1: mov r1,r15";
164 }
165 [(set_attr "length" "20")])
166
167 (define_expand "atomic_exchange<mode>"
168 [(match_operand:I124 0 "register_operand" "") ;; oldval output
169 (match_operand:I124 1 "memory_operand" "") ;; memory
170 (match_operand:I124 2 "register_operand" "") ;; newval input
171 (match_operand:SI 3 "const_int_operand" "")] ;; memory model
172 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
173 {
174 rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
175 emit_insn (gen_atomic_exchange<mode>_soft
176 (operands[0], addr, operands[2]));
177 if (<MODE>mode == QImode)
178 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
179 operands[0]));
180 else if (<MODE>mode == HImode)
181 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
182 operands[0]));
183 DONE;
184 })
185
186 (define_insn "atomic_exchange<mode>_soft"
187 [(set (match_operand:I124 0 "register_operand" "=&u")
188 (mem:I124 (match_operand:SI 1 "register_operand" "u")))
189 (set (mem:I124 (match_dup 1))
190 (unspec:I124
191 [(match_operand:I124 2 "register_operand" "u")] UNSPEC_ATOMIC))
192 (clobber (reg:SI R0_REG))
193 (clobber (reg:SI R1_REG))]
194 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
195 {
196 return "mova 1f,r0" "\n"
197 " .align 2" "\n"
198 " mov r15,r1" "\n"
199 " mov #(0f-1f),r15" "\n"
200 "0: mov.<i124suffix> @%1,%0" "\n"
201 " mov.<i124suffix> %2,@%1" "\n"
202 "1: mov r1,r15";
203 }
204 [(set_attr "length" "14")])
205
206 (define_expand "atomic_fetch_<fetchop_name><mode>"
207 [(set (match_operand:I124 0 "register_operand" "")
208 (match_operand:I124 1 "memory_operand" ""))
209 (set (match_dup 1)
210 (unspec:I124
211 [(FETCHOP:I124 (match_dup 1)
212 (match_operand:I124 2 "register_operand" ""))]
213 UNSPEC_ATOMIC))
214 (match_operand:SI 3 "const_int_operand" "")]
215 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
216 {
217 rtx addr;
218
219 addr = force_reg (Pmode, XEXP (operands[1], 0));
220 emit_insn (gen_atomic_fetch_<fetchop_name><mode>_soft
221 (operands[0], addr, operands[2]));
222 if (<MODE>mode == QImode)
223 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
224 operands[0]));
225 else if (<MODE>mode == HImode)
226 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
227 operands[0]));
228 DONE;
229 })
230
231 (define_insn "atomic_fetch_<fetchop_name><mode>_soft"
232 [(set (match_operand:I124 0 "register_operand" "=&u")
233 (mem:I124 (match_operand:SI 1 "register_operand" "u")))
234 (set (mem:I124 (match_dup 1))
235 (unspec:I124
236 [(FETCHOP:I124 (mem:I124 (match_dup 1))
237 (match_operand:I124 2 "register_operand" "u"))]
238 UNSPEC_ATOMIC))
239 (clobber (match_scratch:I124 3 "=&u"))
240 (clobber (reg:SI R0_REG))
241 (clobber (reg:SI R1_REG))]
242 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
243 {
244 return "mova 1f,r0" "\n"
245 " .align 2" "\n"
246 " mov r15,r1" "\n"
247 " mov #(0f-1f),r15" "\n"
248 "0: mov.<i124suffix> @%1,%0" "\n"
249 " mov %0,%3" "\n"
250 " <fetchop_name> %2,%3" "\n"
251 " mov.<i124suffix> %3,@%1" "\n"
252 "1: mov r1,r15";
253 }
254 [(set_attr "length" "18")])
255
256 (define_expand "atomic_fetch_nand<mode>"
257 [(set (match_operand:I124 0 "register_operand" "")
258 (match_operand:I124 1 "memory_operand" ""))
259 (set (match_dup 1)
260 (unspec:I124
261 [(not:I124 (and:I124 (match_dup 1)
262 (match_operand:I124 2 "register_operand" "")))]
263 UNSPEC_ATOMIC))
264 (match_operand:SI 3 "const_int_operand" "")]
265 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
266 {
267 rtx addr;
268
269 addr = force_reg (Pmode, XEXP (operands[1], 0));
270 emit_insn (gen_atomic_fetch_nand<mode>_soft
271 (operands[0], addr, operands[2]));
272 if (<MODE>mode == QImode)
273 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
274 operands[0]));
275 else if (<MODE>mode == HImode)
276 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
277 operands[0]));
278 DONE;
279 })
280
281 (define_insn "atomic_fetch_nand<mode>_soft"
282 [(set (match_operand:I124 0 "register_operand" "=&u")
283 (mem:I124 (match_operand:SI 1 "register_operand" "u")))
284 (set (mem:I124 (match_dup 1))
285 (unspec:I124
286 [(not:I124 (and:I124 (mem:I124 (match_dup 1))
287 (match_operand:I124 2 "register_operand" "u")))]
288 UNSPEC_ATOMIC))
289 (clobber (match_scratch:I124 3 "=&u"))
290 (clobber (reg:SI R0_REG))
291 (clobber (reg:SI R1_REG))]
292 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
293 {
294 return "mova 1f,r0" "\n"
295 " mov r15,r1" "\n"
296 " .align 2" "\n"
297 " mov #(0f-1f),r15" "\n"
298 "0: mov.<i124suffix> @%1,%0" "\n"
299 " mov %2,%3" "\n"
300 " and %0,%3" "\n"
301 " not %3,%3" "\n"
302 " mov.<i124suffix> %3,@%1" "\n"
303 "1: mov r1,r15";
304 }
305 [(set_attr "length" "20")])
306
307 (define_expand "atomic_<fetchop_name>_fetch<mode>"
308 [(set (match_operand:I124 0 "register_operand" "")
309 (FETCHOP:I124
310 (match_operand:I124 1 "memory_operand" "")
311 (match_operand:I124 2 "register_operand" "")))
312 (set (match_dup 1)
313 (unspec:I124
314 [(FETCHOP:I124 (match_dup 1) (match_dup 2))]
315 UNSPEC_ATOMIC))
316 (match_operand:SI 3 "const_int_operand" "")]
317 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
318 {
319 rtx addr;
320
321 addr = force_reg (Pmode, XEXP (operands[1], 0));
322 emit_insn (gen_atomic_<fetchop_name>_fetch<mode>_soft
323 (operands[0], addr, operands[2]));
324 if (<MODE>mode == QImode)
325 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
326 operands[0]));
327 else if (<MODE>mode == HImode)
328 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
329 operands[0]));
330 DONE;
331 })
332
333 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft"
334 [(set (match_operand:I124 0 "register_operand" "=&u")
335 (FETCHOP:I124
336 (mem:I124 (match_operand:SI 1 "register_operand" "u"))
337 (match_operand:I124 2 "register_operand" "u")))
338 (set (mem:I124 (match_dup 1))
339 (unspec:I124
340 [(FETCHOP:I124 (mem:I124 (match_dup 1)) (match_dup 2))]
341 UNSPEC_ATOMIC))
342 (clobber (reg:SI R0_REG))
343 (clobber (reg:SI R1_REG))]
344 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
345 {
346 return "mova 1f,r0" "\n"
347 " mov r15,r1" "\n"
348 " .align 2" "\n"
349 " mov #(0f-1f),r15" "\n"
350 "0: mov.<i124suffix> @%1,%0" "\n"
351 " <fetchop_name> %2,%0" "\n"
352 " mov.<i124suffix> %0,@%1" "\n"
353 "1: mov r1,r15";
354 }
355 [(set_attr "length" "16")])
356
357 (define_expand "atomic_nand_fetch<mode>"
358 [(set (match_operand:I124 0 "register_operand" "")
359 (not:I124 (and:I124
360 (match_operand:I124 1 "memory_operand" "")
361 (match_operand:I124 2 "register_operand" ""))))
362 (set (match_dup 1)
363 (unspec:I124
364 [(not:I124 (and:I124 (match_dup 1) (match_dup 2)))]
365 UNSPEC_ATOMIC))
366 (match_operand:SI 3 "const_int_operand" "")]
367 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
368 {
369 rtx addr;
370
371 addr = force_reg (Pmode, XEXP (operands[1], 0));
372 emit_insn (gen_atomic_nand_fetch<mode>_soft
373 (operands[0], addr, operands[2]));
374 if (<MODE>mode == QImode)
375 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
376 operands[0]));
377 else if (<MODE>mode == HImode)
378 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
379 operands[0]));
380 DONE;
381 })
382
383 (define_insn "atomic_nand_fetch<mode>_soft"
384 [(set (match_operand:I124 0 "register_operand" "=&u")
385 (not:I124 (and:I124
386 (mem:I124 (match_operand:SI 1 "register_operand" "u"))
387 (match_operand:I124 2 "register_operand" "u"))))
388 (set (mem:I124 (match_dup 1))
389 (unspec:I124
390 [(not:I124 (and:I124 (mem:I124 (match_dup 1)) (match_dup 2)))]
391 UNSPEC_ATOMIC))
392 (clobber (reg:SI R0_REG))
393 (clobber (reg:SI R1_REG))]
394 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
395 {
396 return "mova 1f,r0" "\n"
397 " .align 2" "\n"
398 " mov r15,r1" "\n"
399 " mov #(0f-1f),r15" "\n"
400 "0: mov.<i124suffix> @%1,%0" "\n"
401 " and %2,%0" "\n"
402 " not %0,%0" "\n"
403 " mov.<i124suffix> %0,@%1" "\n"
404 "1: mov r1,r15";
405 }
406 [(set_attr "length" "18")])
407
408 (define_expand "atomic_test_and_set"
409 [(match_operand:SI 0 "register_operand" "") ;; bool result output
410 (match_operand:QI 1 "memory_operand" "") ;; memory
411 (match_operand:SI 2 "const_int_operand" "")] ;; model
412 "(TARGET_SOFT_ATOMIC || TARGET_ENABLE_TAS) && !TARGET_SHMEDIA"
413 {
414 rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
415
416 if (TARGET_ENABLE_TAS)
417 emit_insn (gen_tasb (addr));
418 else
419 {
420 rtx val = force_reg (QImode,
421 gen_int_mode (TARGET_ATOMIC_TEST_AND_SET_TRUEVAL,
422 QImode));
423 emit_insn (gen_atomic_test_and_set_soft (addr, val));
424 }
425
426 /* The result of the test op is the inverse of what we are
427 supposed to return. Thus invert the T bit. The inversion will be
428 potentially optimized away and integrated into surrounding code. */
429 emit_insn (gen_movnegt (operands[0]));
430 DONE;
431 })
432
433 (define_insn "tasb"
434 [(set (reg:SI T_REG)
435 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
436 (const_int 0)))
437 (set (mem:QI (match_dup 0))
438 (unspec:QI [(const_int 128)] UNSPEC_ATOMIC))]
439 "TARGET_ENABLE_TAS && !TARGET_SHMEDIA"
440 "tas.b @%0"
441 [(set_attr "insn_class" "co_group")])
442
443 (define_insn "atomic_test_and_set_soft"
444 [(set (reg:SI T_REG)
445 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "u"))
446 (const_int 0)))
447 (set (mem:QI (match_dup 0))
448 (unspec:QI [(match_operand:QI 1 "register_operand" "u")] UNSPEC_ATOMIC))
449 (clobber (match_scratch:QI 2 "=&u"))
450 (clobber (reg:SI R0_REG))
451 (clobber (reg:SI R1_REG))]
452 "TARGET_SOFT_ATOMIC && !TARGET_ENABLE_TAS && !TARGET_SHMEDIA"
453 {
454 return "mova 1f,r0" "\n"
455 " .align 2" "\n"
456 " mov r15,r1" "\n"
457 " mov #(0f-1f),r15" "\n"
458 "0: mov.b @%0,%2" "\n"
459 " mov.b %1,@%0" "\n"
460 "1: mov r1,r15" "\n"
461 " tst %2,%2";
462 }
463 [(set_attr "length" "16")])
464