1 ;; GCC machine description for SH synchronization instructions.
2 ;; Copyright (C) 2011, 2012
3 ;; Free Software Foundation, Inc.
5 ;; This file is part of GCC.
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)
12 ;; GCC is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GCC; see the file COPYING3. If not see
19 ;; <http://www.gnu.org/licenses/>.
22 ;; Atomic integer operations for the Renesas / SuperH SH CPUs.
24 ;; On 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
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
34 ;; if (interrupted_context_in_atomic_sequence
35 ;; && interrupted_pc < atomic_exitpoint)
36 ;; interrupted_pc = atomic_entrypoint;
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
43 ;; For this the following atomic sequence ABI is used.
45 ;; r15 >= 0: Execution context is not in an atomic sequence.
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:
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.
56 ;; r1: Saved r15 stack pointer before entering the
59 ;; An example atomic add sequence would look like:
61 ;; mova .Lend,r0 ! .Lend must be 4-byte aligned.
63 ;; .align 2 ! Insert aligning nop if needed.
64 ;; mov #(.Lstart - .Lend),r15 ! Enter atomic sequence
66 ;; mov.l @r4,r2 ! read value
67 ;; add r2,r5 ! modify value
68 ;; mov.l r5,@r4 ! write-back
70 ;; mov r1,r15 ! Exit atomic sequence
71 ;; ! r2 holds the previous value.
72 ;; ! r5 holds the new value.
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.
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.
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.
92 (define_c_enum "unspec" [
96 (define_c_enum "unspecv" [
102 (define_mode_iterator I124 [QI HI SI])
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")])
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")])
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"
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],
128 if (<MODE>mode == QImode)
129 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[1]),
131 else if (<MODE>mode == HImode)
132 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[1]),
134 emit_insn (gen_movsi (operands[0], gen_rtx_REG (SImode, T_REG)));
138 (define_insn "atomic_compare_and_swap<mode>_soft"
139 [(set (match_operand:SI 0 "register_operand" "=&u")
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")]
145 (set (mem:I124 (match_dup 1))
146 (unspec_volatile:I124 [(const_int 0)] UNSPECV_CMPXCHG_2))
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"
154 return "mova 1f,r0" "\n"
155 " <i124extend_insn> %2,%4" "\n"
158 " mov #(0f-1f),r15" "\n"
159 "0: mov.<i124suffix> @%1,%0" "\n"
162 " mov.<i124suffix> %3,@%1" "\n"
165 [(set_attr "length" "20")])
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"
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]),
180 else if (<MODE>mode == HImode)
181 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
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))
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"
196 return "mova 1f,r0" "\n"
199 " mov #(0f-1f),r15" "\n"
200 "0: mov.<i124suffix> @%1,%0" "\n"
201 " mov.<i124suffix> %2,@%1" "\n"
204 [(set_attr "length" "14")])
206 (define_expand "atomic_fetch_<fetchop_name><mode>"
207 [(set (match_operand:I124 0 "register_operand" "")
208 (match_operand:I124 1 "memory_operand" ""))
211 [(FETCHOP:I124 (match_dup 1)
212 (match_operand:I124 2 "register_operand" ""))]
214 (match_operand:SI 3 "const_int_operand" "")]
215 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
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]),
225 else if (<MODE>mode == HImode)
226 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
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))
236 [(FETCHOP:I124 (mem:I124 (match_dup 1))
237 (match_operand:I124 2 "register_operand" "u"))]
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"
244 return "mova 1f,r0" "\n"
247 " mov #(0f-1f),r15" "\n"
248 "0: mov.<i124suffix> @%1,%0" "\n"
250 " <fetchop_name> %2,%3" "\n"
251 " mov.<i124suffix> %3,@%1" "\n"
254 [(set_attr "length" "18")])
256 (define_expand "atomic_fetch_nand<mode>"
257 [(set (match_operand:I124 0 "register_operand" "")
258 (match_operand:I124 1 "memory_operand" ""))
261 [(not:I124 (and:I124 (match_dup 1)
262 (match_operand:I124 2 "register_operand" "")))]
264 (match_operand:SI 3 "const_int_operand" "")]
265 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
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]),
275 else if (<MODE>mode == HImode)
276 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
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))
286 [(not:I124 (and:I124 (mem:I124 (match_dup 1))
287 (match_operand:I124 2 "register_operand" "u")))]
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"
294 return "mova 1f,r0" "\n"
297 " mov #(0f-1f),r15" "\n"
298 "0: mov.<i124suffix> @%1,%0" "\n"
302 " mov.<i124suffix> %3,@%1" "\n"
305 [(set_attr "length" "20")])
307 (define_expand "atomic_<fetchop_name>_fetch<mode>"
308 [(set (match_operand:I124 0 "register_operand" "")
310 (match_operand:I124 1 "memory_operand" "")
311 (match_operand:I124 2 "register_operand" "")))
314 [(FETCHOP:I124 (match_dup 1) (match_dup 2))]
316 (match_operand:SI 3 "const_int_operand" "")]
317 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
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]),
327 else if (<MODE>mode == HImode)
328 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
333 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft"
334 [(set (match_operand:I124 0 "register_operand" "=&u")
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))
340 [(FETCHOP:I124 (mem:I124 (match_dup 1)) (match_dup 2))]
342 (clobber (reg:SI R0_REG))
343 (clobber (reg:SI R1_REG))]
344 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
346 return "mova 1f,r0" "\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"
355 [(set_attr "length" "16")])
357 (define_expand "atomic_nand_fetch<mode>"
358 [(set (match_operand:I124 0 "register_operand" "")
360 (match_operand:I124 1 "memory_operand" "")
361 (match_operand:I124 2 "register_operand" ""))))
364 [(not:I124 (and:I124 (match_dup 1) (match_dup 2)))]
366 (match_operand:SI 3 "const_int_operand" "")]
367 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
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]),
377 else if (<MODE>mode == HImode)
378 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
383 (define_insn "atomic_nand_fetch<mode>_soft"
384 [(set (match_operand:I124 0 "register_operand" "=&u")
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))
390 [(not:I124 (and:I124 (mem:I124 (match_dup 1)) (match_dup 2)))]
392 (clobber (reg:SI R0_REG))
393 (clobber (reg:SI R1_REG))]
394 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
396 return "mova 1f,r0" "\n"
399 " mov #(0f-1f),r15" "\n"
400 "0: mov.<i124suffix> @%1,%0" "\n"
403 " mov.<i124suffix> %0,@%1" "\n"
406 [(set_attr "length" "18")])
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"
414 rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
416 if (TARGET_ENABLE_TAS)
417 emit_insn (gen_tasb (addr));
422 val = gen_int_mode (targetm.atomic_test_and_set_trueval, QImode);
423 val = force_reg (QImode, val);
424 emit_insn (gen_atomic_test_and_set_soft (addr, val));
427 /* The result of the test op is the inverse of what we are
428 supposed to return. Thus invert the T bit. The inversion will be
429 potentially optimized away and integrated into surrounding code. */
430 emit_insn (gen_movnegt (operands[0]));
436 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "r"))
438 (set (mem:QI (match_dup 0))
439 (unspec:QI [(const_int 128)] UNSPEC_ATOMIC))]
440 "TARGET_ENABLE_TAS && !TARGET_SHMEDIA"
442 [(set_attr "insn_class" "co_group")])
444 (define_insn "atomic_test_and_set_soft"
446 (eq:SI (mem:QI (match_operand:SI 0 "register_operand" "u"))
448 (set (mem:QI (match_dup 0))
449 (unspec:QI [(match_operand:QI 1 "register_operand" "u")] UNSPEC_ATOMIC))
450 (clobber (match_scratch:QI 2 "=&u"))
451 (clobber (reg:SI R0_REG))
452 (clobber (reg:SI R1_REG))]
453 "TARGET_SOFT_ATOMIC && !TARGET_ENABLE_TAS && !TARGET_SHMEDIA"
455 return "mova 1f,r0" "\n"
458 " mov #(0f-1f),r15" "\n"
459 "0: mov.b @%0,%2" "\n"
464 [(set_attr "length" "16")])