sync.md: Add soft atomics ABI description.
[gcc.git] / gcc / config / sh / sync.md
1 ;; GCC machine description for SH synchronization instructions.
2 ;; Copyright (C) 2011
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:QI 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_movqi (operands[0], gen_rtx_REG (QImode, 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:QI T_REG)
148 (unspec_volatile:QI [(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_fetch_<fetchop_name><mode>"
168 [(set (match_operand:I124 0 "register_operand" "")
169 (match_operand:I124 1 "memory_operand" ""))
170 (set (match_dup 1)
171 (unspec:I124
172 [(FETCHOP:I124 (match_dup 1)
173 (match_operand:I124 2 "register_operand" ""))]
174 UNSPEC_ATOMIC))
175 (match_operand:SI 3 "const_int_operand" "")]
176 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
177 {
178 rtx addr;
179
180 addr = force_reg (Pmode, XEXP (operands[1], 0));
181 emit_insn (gen_atomic_fetch_<fetchop_name><mode>_soft
182 (operands[0], addr, operands[2]));
183 if (<MODE>mode == QImode)
184 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
185 operands[0]));
186 else if (<MODE>mode == HImode)
187 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
188 operands[0]));
189 DONE;
190 })
191
192 (define_insn "atomic_fetch_<fetchop_name><mode>_soft"
193 [(set (match_operand:I124 0 "register_operand" "=&u")
194 (mem:I124 (match_operand:SI 1 "register_operand" "u")))
195 (set (mem:I124 (match_dup 1))
196 (unspec:I124
197 [(FETCHOP:I124 (mem:I124 (match_dup 1))
198 (match_operand:I124 2 "register_operand" "u"))]
199 UNSPEC_ATOMIC))
200 (clobber (match_scratch:I124 3 "=&u"))
201 (clobber (reg:SI R0_REG))
202 (clobber (reg:SI R1_REG))]
203 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
204 {
205 return "mova 1f,r0" "\n"
206 " .align 2" "\n"
207 " mov r15,r1" "\n"
208 " mov #(0f-1f),r15" "\n"
209 "0: mov.<i124suffix> @%1,%0" "\n"
210 " mov %0,%3" "\n"
211 " <fetchop_name> %2,%3" "\n"
212 " mov.<i124suffix> %3,@%1" "\n"
213 "1: mov r1,r15";
214 }
215 [(set_attr "length" "18")])
216
217 (define_expand "atomic_fetch_nand<mode>"
218 [(set (match_operand:I124 0 "register_operand" "")
219 (match_operand:I124 1 "memory_operand" ""))
220 (set (match_dup 1)
221 (unspec:I124
222 [(not:I124 (and:I124 (match_dup 1)
223 (match_operand:I124 2 "register_operand" "")))]
224 UNSPEC_ATOMIC))
225 (match_operand:SI 3 "const_int_operand" "")]
226 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
227 {
228 rtx addr;
229
230 addr = force_reg (Pmode, XEXP (operands[1], 0));
231 emit_insn (gen_atomic_fetch_nand<mode>_soft
232 (operands[0], addr, operands[2]));
233 if (<MODE>mode == QImode)
234 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
235 operands[0]));
236 else if (<MODE>mode == HImode)
237 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
238 operands[0]));
239 DONE;
240 })
241
242 (define_insn "atomic_fetch_nand<mode>_soft"
243 [(set (match_operand:I124 0 "register_operand" "=&u")
244 (mem:I124 (match_operand:SI 1 "register_operand" "u")))
245 (set (mem:I124 (match_dup 1))
246 (unspec:I124
247 [(not:I124 (and:I124 (mem:I124 (match_dup 1))
248 (match_operand:I124 2 "register_operand" "u")))]
249 UNSPEC_ATOMIC))
250 (clobber (match_scratch:I124 3 "=&u"))
251 (clobber (reg:SI R0_REG))
252 (clobber (reg:SI R1_REG))]
253 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
254 {
255 return "mova 1f,r0" "\n"
256 " mov r15,r1" "\n"
257 " .align 2" "\n"
258 " mov #(0f-1f),r15" "\n"
259 "0: mov.<i124suffix> @%1,%0" "\n"
260 " mov %2,%3" "\n"
261 " and %0,%3" "\n"
262 " not %3,%3" "\n"
263 " mov.<i124suffix> %3,@%1" "\n"
264 "1: mov r1,r15";
265 }
266 [(set_attr "length" "20")])
267
268 (define_expand "atomic_<fetchop_name>_fetch<mode>"
269 [(set (match_operand:I124 0 "register_operand" "")
270 (FETCHOP:I124
271 (match_operand:I124 1 "memory_operand" "")
272 (match_operand:I124 2 "register_operand" "")))
273 (set (match_dup 1)
274 (unspec:I124
275 [(FETCHOP:I124 (match_dup 1) (match_dup 2))]
276 UNSPEC_ATOMIC))
277 (match_operand:SI 3 "const_int_operand" "")]
278 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
279 {
280 rtx addr;
281
282 addr = force_reg (Pmode, XEXP (operands[1], 0));
283 emit_insn (gen_atomic_<fetchop_name>_fetch<mode>_soft
284 (operands[0], addr, operands[2]));
285 if (<MODE>mode == QImode)
286 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
287 operands[0]));
288 else if (<MODE>mode == HImode)
289 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
290 operands[0]));
291 DONE;
292 })
293
294 (define_insn "atomic_<fetchop_name>_fetch<mode>_soft"
295 [(set (match_operand:I124 0 "register_operand" "=&u")
296 (FETCHOP:I124
297 (mem:I124 (match_operand:SI 1 "register_operand" "u"))
298 (match_operand:I124 2 "register_operand" "u")))
299 (set (mem:I124 (match_dup 1))
300 (unspec:I124
301 [(FETCHOP:I124 (mem:I124 (match_dup 1)) (match_dup 2))]
302 UNSPEC_ATOMIC))
303 (clobber (reg:SI R0_REG))
304 (clobber (reg:SI R1_REG))]
305 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
306 {
307 return "mova 1f,r0" "\n"
308 " mov r15,r1" "\n"
309 " .align 2" "\n"
310 " mov #(0f-1f),r15" "\n"
311 "0: mov.<i124suffix> @%1,%0" "\n"
312 " <fetchop_name> %2,%0" "\n"
313 " mov.<i124suffix> %0,@%1" "\n"
314 "1: mov r1,r15";
315 }
316 [(set_attr "length" "16")])
317
318 (define_expand "atomic_nand_fetch<mode>"
319 [(set (match_operand:I124 0 "register_operand" "")
320 (not:I124 (and:I124
321 (match_operand:I124 1 "memory_operand" "")
322 (match_operand:I124 2 "register_operand" ""))))
323 (set (match_dup 1)
324 (unspec:I124
325 [(not:I124 (and:I124 (match_dup 1) (match_dup 2)))]
326 UNSPEC_ATOMIC))
327 (match_operand:SI 3 "const_int_operand" "")]
328 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
329 {
330 rtx addr;
331
332 addr = force_reg (Pmode, XEXP (operands[1], 0));
333 emit_insn (gen_atomic_nand_fetch<mode>_soft
334 (operands[0], addr, operands[2]));
335 if (<MODE>mode == QImode)
336 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, operands[0]),
337 operands[0]));
338 else if (<MODE>mode == HImode)
339 emit_insn (gen_zero_extendhisi2 (gen_lowpart (SImode, operands[0]),
340 operands[0]));
341 DONE;
342 })
343
344 (define_insn "atomic_nand_fetch<mode>_soft"
345 [(set (match_operand:I124 0 "register_operand" "=&u")
346 (not:I124 (and:I124
347 (mem:I124 (match_operand:SI 1 "register_operand" "u"))
348 (match_operand:I124 2 "register_operand" "u"))))
349 (set (mem:I124 (match_dup 1))
350 (unspec:I124
351 [(not:I124 (and:I124 (mem:I124 (match_dup 1)) (match_dup 2)))]
352 UNSPEC_ATOMIC))
353 (clobber (reg:SI R0_REG))
354 (clobber (reg:SI R1_REG))]
355 "TARGET_SOFT_ATOMIC && !TARGET_SHMEDIA"
356 {
357 return "mova 1f,r0" "\n"
358 " .align 2" "\n"
359 " mov r15,r1" "\n"
360 " mov #(0f-1f),r15" "\n"
361 "0: mov.<i124suffix> @%1,%0" "\n"
362 " and %2,%0" "\n"
363 " not %0,%0" "\n"
364 " mov.<i124suffix> %0,@%1" "\n"
365 "1: mov r1,r15";
366 }
367 [(set_attr "length" "18")])