]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/rs6000/sync.md
Update copyright years.
[thirdparty/gcc.git] / gcc / config / rs6000 / sync.md
CommitLineData
f565b0a1 1;; Machine description for PowerPC synchronization instructions.
818ab71a 2;; Copyright (C) 2005-2016 Free Software Foundation, Inc.
f565b0a1
DE
3;; Contributed by Geoffrey Keating.
4
5;; This file is part of GCC.
6
7;; GCC is free software; you can redistribute it and/or modify it
8;; under the terms of the GNU General Public License as published
2f83c7d6 9;; by the Free Software Foundation; either version 3, or (at your
f565b0a1
DE
10;; option) any later version.
11
12;; GCC is distributed in the hope that it will be useful, but WITHOUT
13;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15;; License for more details.
16
17;; You should have received a copy of the GNU General Public License
2f83c7d6
NC
18;; along with GCC; see the file COPYING3. If not see
19;; <http://www.gnu.org/licenses/>.
f565b0a1 20
4b02c962
MM
21(define_mode_attr larx [(QI "lbarx")
22 (HI "lharx")
23 (SI "lwarx")
24 (DI "ldarx")
25 (TI "lqarx")])
26
27(define_mode_attr stcx [(QI "stbcx.")
28 (HI "sthcx.")
29 (SI "stwcx.")
30 (DI "stdcx.")
31 (TI "stqcx.")])
f565b0a1 32
3abcb3a7 33(define_code_iterator FETCHOP [plus minus ior xor and])
9f0076e5 34(define_code_attr fetchop_name
3877ce45 35 [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")])
9f0076e5 36(define_code_attr fetchop_pred
4b02c962 37 [(plus "add_operand") (minus "int_reg_operand")
9f0076e5 38 (ior "logical_operand") (xor "logical_operand") (and "and_operand")])
9f0076e5 39
2747a046
RH
40(define_expand "mem_thread_fence"
41 [(match_operand:SI 0 "const_int_operand" "")] ;; model
42 ""
43{
39e150e8 44 enum memmodel model = memmodel_base (INTVAL (operands[0]));
2747a046
RH
45 switch (model)
46 {
47 case MEMMODEL_RELAXED:
48 break;
49 case MEMMODEL_CONSUME:
50 case MEMMODEL_ACQUIRE:
51 case MEMMODEL_RELEASE:
52 case MEMMODEL_ACQ_REL:
53 emit_insn (gen_lwsync ());
54 break;
55 case MEMMODEL_SEQ_CST:
56 emit_insn (gen_hwsync ());
57 break;
58 default:
59 gcc_unreachable ();
60 }
61 DONE;
62})
63
64(define_expand "hwsync"
1a8c13b3
UB
65 [(set (match_dup 0)
66 (unspec:BLK [(match_dup 0)] UNSPEC_SYNC))]
f565b0a1 67 ""
b52110d4
DE
68{
69 operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
70 MEM_VOLATILE_P (operands[0]) = 1;
71})
72
2747a046 73(define_insn "*hwsync"
b52110d4 74 [(set (match_operand:BLK 0 "" "")
1a8c13b3 75 (unspec:BLK [(match_dup 0)] UNSPEC_SYNC))]
b52110d4 76 ""
6b39bc38 77 "sync"
b52110d4
DE
78 [(set_attr "type" "sync")])
79
2747a046
RH
80(define_expand "lwsync"
81 [(set (match_dup 0)
82 (unspec:BLK [(match_dup 0)] UNSPEC_LWSYNC))]
83 ""
b52110d4 84{
2747a046
RH
85 operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
86 MEM_VOLATILE_P (operands[0]) = 1;
b52110d4 87})
f565b0a1 88
2747a046
RH
89(define_insn "*lwsync"
90 [(set (match_operand:BLK 0 "" "")
91 (unspec:BLK [(match_dup 0)] UNSPEC_LWSYNC))]
92 ""
9fc75b97 93{
2747a046
RH
94 /* Some AIX assemblers don't accept lwsync, so we use a .long. */
95 if (TARGET_NO_LWSYNC)
96 return "sync";
97 else if (TARGET_LWSYNC_INSTRUCTION)
98 return "lwsync";
99 else
100 return ".long 0x7c2004ac";
101}
102 [(set_attr "type" "sync")])
9fc75b97 103
2747a046
RH
104(define_insn "isync"
105 [(unspec_volatile:BLK [(const_int 0)] UNSPECV_ISYNC)]
106 ""
6b39bc38 107 "isync"
2747a046 108 [(set_attr "type" "isync")])
9fc75b97 109
bf245bf4
PH
110;; Types that we should provide atomic instructions for.
111(define_mode_iterator AINT [QI
112 HI
113 SI
114 (DI "TARGET_POWERPC64")
115 (TI "TARGET_SYNC_TI")])
116
2747a046
RH
117;; The control dependency used for load dependency described
118;; in B.2.3 of the Power ISA 2.06B.
1ba24090 119(define_insn "loadsync_<mode>"
bf245bf4 120 [(unspec_volatile:BLK [(match_operand:AINT 0 "register_operand" "r")]
2747a046
RH
121 UNSPECV_ISYNC)
122 (clobber (match_scratch:CC 1 "=y"))]
123 ""
124 "cmpw %1,%0,%0\;bne- %1,$+4\;isync"
125 [(set_attr "type" "isync")
126 (set_attr "length" "12")])
127
bf245bf4
PH
128(define_insn "load_quadpti"
129 [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r")
130 (unspec:PTI
131 [(match_operand:TI 1 "quad_memory_operand" "wQ")] UNSPEC_LSQ))]
132 "TARGET_SYNC_TI
133 && !reg_mentioned_p (operands[0], operands[1])"
134 "lq %0,%1"
135 [(set_attr "type" "load")
136 (set_attr "length" "4")])
137
2747a046 138(define_expand "atomic_load<mode>"
bf245bf4
PH
139 [(set (match_operand:AINT 0 "register_operand" "") ;; output
140 (match_operand:AINT 1 "memory_operand" "")) ;; memory
2747a046
RH
141 (use (match_operand:SI 2 "const_int_operand" ""))] ;; model
142 ""
9fc75b97 143{
bf245bf4
PH
144 if (<MODE>mode == TImode && !TARGET_SYNC_TI)
145 FAIL;
146
39e150e8 147 enum memmodel model = memmodel_base (INTVAL (operands[2]));
9fc75b97 148
46b35980 149 if (is_mm_seq_cst (model))
2747a046 150 emit_insn (gen_hwsync ());
f565b0a1 151
bf245bf4
PH
152 if (<MODE>mode != TImode)
153 emit_move_insn (operands[0], operands[1]);
154 else
155 {
156 rtx op0 = operands[0];
157 rtx op1 = operands[1];
158 rtx pti_reg = gen_reg_rtx (PTImode);
159
160 // Can't have indexed address for 'lq'
161 if (indexed_address (XEXP (op1, 0), TImode))
162 {
163 rtx old_addr = XEXP (op1, 0);
164 rtx new_addr = force_reg (Pmode, old_addr);
165 operands[1] = op1 = replace_equiv_address (op1, new_addr);
166 }
167
168 emit_insn (gen_load_quadpti (pti_reg, op1));
169
170 if (WORDS_BIG_ENDIAN)
171 emit_move_insn (op0, gen_lowpart (TImode, pti_reg));
172 else
173 {
174 emit_move_insn (gen_lowpart (DImode, op0), gen_highpart (DImode, pti_reg));
175 emit_move_insn (gen_highpart (DImode, op0), gen_lowpart (DImode, pti_reg));
176 }
177 }
2747a046
RH
178
179 switch (model)
9f0076e5 180 {
2747a046
RH
181 case MEMMODEL_RELAXED:
182 break;
183 case MEMMODEL_CONSUME:
184 case MEMMODEL_ACQUIRE:
185 case MEMMODEL_SEQ_CST:
4b02c962 186 emit_insn (gen_loadsync_<mode> (operands[0]));
2747a046
RH
187 break;
188 default:
189 gcc_unreachable ();
9f0076e5 190 }
f565b0a1 191 DONE;
9f0076e5 192})
f565b0a1 193
bf245bf4
PH
194(define_insn "store_quadpti"
195 [(set (match_operand:PTI 0 "quad_memory_operand" "=wQ")
196 (unspec:PTI
197 [(match_operand:PTI 1 "quad_int_reg_operand" "r")] UNSPEC_LSQ))]
198 "TARGET_SYNC_TI"
199 "stq %1,%0"
200 [(set_attr "type" "store")
201 (set_attr "length" "4")])
202
2747a046 203(define_expand "atomic_store<mode>"
bf245bf4
PH
204 [(set (match_operand:AINT 0 "memory_operand" "") ;; memory
205 (match_operand:AINT 1 "register_operand" "")) ;; input
2747a046
RH
206 (use (match_operand:SI 2 "const_int_operand" ""))] ;; model
207 ""
f565b0a1 208{
bf245bf4
PH
209 if (<MODE>mode == TImode && !TARGET_SYNC_TI)
210 FAIL;
211
39e150e8 212 enum memmodel model = memmodel_base (INTVAL (operands[2]));
2747a046
RH
213 switch (model)
214 {
215 case MEMMODEL_RELAXED:
216 break;
217 case MEMMODEL_RELEASE:
218 emit_insn (gen_lwsync ());
219 break;
220 case MEMMODEL_SEQ_CST:
221 emit_insn (gen_hwsync ());
222 break;
223 default:
224 gcc_unreachable ();
225 }
bf245bf4
PH
226 if (<MODE>mode != TImode)
227 emit_move_insn (operands[0], operands[1]);
228 else
229 {
230 rtx op0 = operands[0];
231 rtx op1 = operands[1];
232 rtx pti_reg = gen_reg_rtx (PTImode);
233
234 // Can't have indexed address for 'stq'
235 if (indexed_address (XEXP (op0, 0), TImode))
236 {
237 rtx old_addr = XEXP (op0, 0);
238 rtx new_addr = force_reg (Pmode, old_addr);
239 operands[0] = op0 = replace_equiv_address (op0, new_addr);
240 }
241
242 if (WORDS_BIG_ENDIAN)
243 emit_move_insn (pti_reg, gen_lowpart (PTImode, op1));
244 else
245 {
246 emit_move_insn (gen_lowpart (DImode, pti_reg), gen_highpart (DImode, op1));
247 emit_move_insn (gen_highpart (DImode, pti_reg), gen_lowpart (DImode, op1));
248 }
249
250 emit_insn (gen_store_quadpti (gen_lowpart (PTImode, op0), pti_reg));
251 }
252
f565b0a1 253 DONE;
9f0076e5 254})
f565b0a1 255
4b02c962
MM
256;; Any supported integer mode that has atomic l<x>arx/st<x>cx. instrucitons
257;; other than the quad memory operations, which have special restrictions.
258;; Byte/halfword atomic instructions were added in ISA 2.06B, but were phased
259;; in and did not show up until power8. TImode atomic lqarx/stqcx. require
260;; special handling due to even/odd register requirements.
261(define_mode_iterator ATOMIC [(QI "TARGET_SYNC_HI_QI")
262 (HI "TARGET_SYNC_HI_QI")
263 SI
264 (DI "TARGET_POWERPC64")])
265
2747a046 266(define_insn "load_locked<mode>"
4b02c962 267 [(set (match_operand:ATOMIC 0 "int_reg_operand" "=r")
2747a046
RH
268 (unspec_volatile:ATOMIC
269 [(match_operand:ATOMIC 1 "memory_operand" "Z")] UNSPECV_LL))]
a441dedb 270 ""
2747a046
RH
271 "<larx> %0,%y1"
272 [(set_attr "type" "load_l")])
f565b0a1 273
4b02c962
MM
274(define_insn "load_locked<QHI:mode>_si"
275 [(set (match_operand:SI 0 "int_reg_operand" "=r")
276 (unspec_volatile:SI
277 [(match_operand:QHI 1 "memory_operand" "Z")] UNSPECV_LL))]
278 "TARGET_SYNC_HI_QI"
279 "<QHI:larx> %0,%y1"
280 [(set_attr "type" "load_l")])
281
b846c948
MM
282;; Use PTImode to get even/odd register pairs.
283;; Use a temporary register to force getting an even register for the
284;; lqarx/stqcrx. instructions. Normal optimizations will eliminate this extra
285;; copy on big endian systems.
286
287;; On little endian systems where non-atomic quad word load/store instructions
288;; are not used, the address can be register+offset, so make sure the address
289;; is indexed or indirect before register allocation.
290
4b02c962
MM
291(define_expand "load_lockedti"
292 [(use (match_operand:TI 0 "quad_int_reg_operand" ""))
293 (use (match_operand:TI 1 "memory_operand" ""))]
294 "TARGET_SYNC_TI"
295{
b846c948
MM
296 rtx op0 = operands[0];
297 rtx op1 = operands[1];
4b02c962 298 rtx pti = gen_reg_rtx (PTImode);
b846c948
MM
299
300 if (!indexed_or_indirect_operand (op1, TImode))
301 {
302 rtx old_addr = XEXP (op1, 0);
303 rtx new_addr = force_reg (Pmode, old_addr);
304 operands[1] = op1 = change_address (op1, TImode, new_addr);
305 }
306
307 emit_insn (gen_load_lockedpti (pti, op1));
308 if (WORDS_BIG_ENDIAN)
309 emit_move_insn (op0, gen_lowpart (TImode, pti));
310 else
311 {
312 emit_move_insn (gen_lowpart (DImode, op0), gen_highpart (DImode, pti));
313 emit_move_insn (gen_highpart (DImode, op0), gen_lowpart (DImode, pti));
314 }
4b02c962
MM
315 DONE;
316})
317
318(define_insn "load_lockedpti"
319 [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r")
320 (unspec_volatile:PTI
b846c948 321 [(match_operand:TI 1 "indexed_or_indirect_operand" "Z")] UNSPECV_LL))]
4b02c962
MM
322 "TARGET_SYNC_TI
323 && !reg_mentioned_p (operands[0], operands[1])
324 && quad_int_reg_operand (operands[0], PTImode)"
325 "lqarx %0,%y1"
326 [(set_attr "type" "load_l")])
327
2747a046
RH
328(define_insn "store_conditional<mode>"
329 [(set (match_operand:CC 0 "cc_reg_operand" "=x")
330 (unspec_volatile:CC [(const_int 0)] UNSPECV_SC))
331 (set (match_operand:ATOMIC 1 "memory_operand" "=Z")
4b02c962 332 (match_operand:ATOMIC 2 "int_reg_operand" "r"))]
a441dedb 333 ""
2747a046
RH
334 "<stcx> %2,%y1"
335 [(set_attr "type" "store_c")])
f565b0a1 336
b846c948
MM
337;; Use a temporary register to force getting an even register for the
338;; lqarx/stqcrx. instructions. Normal optimizations will eliminate this extra
339;; copy on big endian systems.
340
341;; On little endian systems where non-atomic quad word load/store instructions
342;; are not used, the address can be register+offset, so make sure the address
343;; is indexed or indirect before register allocation.
344
4b02c962
MM
345(define_expand "store_conditionalti"
346 [(use (match_operand:CC 0 "cc_reg_operand" ""))
347 (use (match_operand:TI 1 "memory_operand" ""))
348 (use (match_operand:TI 2 "quad_int_reg_operand" ""))]
349 "TARGET_SYNC_TI"
350{
351 rtx op0 = operands[0];
352 rtx op1 = operands[1];
353 rtx op2 = operands[2];
b846c948
MM
354 rtx addr = XEXP (op1, 0);
355 rtx pti_mem;
356 rtx pti_reg;
357
358 if (!indexed_or_indirect_operand (op1, TImode))
359 {
360 rtx new_addr = force_reg (Pmode, addr);
361 operands[1] = op1 = change_address (op1, TImode, new_addr);
362 addr = new_addr;
363 }
364
365 pti_mem = change_address (op1, PTImode, addr);
366 pti_reg = gen_reg_rtx (PTImode);
367
368 if (WORDS_BIG_ENDIAN)
369 emit_move_insn (pti_reg, gen_lowpart (PTImode, op2));
370 else
371 {
372 emit_move_insn (gen_lowpart (DImode, pti_reg), gen_highpart (DImode, op2));
373 emit_move_insn (gen_highpart (DImode, pti_reg), gen_lowpart (DImode, op2));
374 }
375
376 emit_insn (gen_store_conditionalpti (op0, pti_mem, pti_reg));
4b02c962
MM
377 DONE;
378})
379
380(define_insn "store_conditionalpti"
381 [(set (match_operand:CC 0 "cc_reg_operand" "=x")
382 (unspec_volatile:CC [(const_int 0)] UNSPECV_SC))
b846c948 383 (set (match_operand:PTI 1 "indexed_or_indirect_operand" "=Z")
4b02c962
MM
384 (match_operand:PTI 2 "quad_int_reg_operand" "r"))]
385 "TARGET_SYNC_TI && quad_int_reg_operand (operands[2], PTImode)"
386 "stqcx. %2,%y1"
387 [(set_attr "type" "store_c")])
388
2747a046 389(define_expand "atomic_compare_and_swap<mode>"
4b02c962
MM
390 [(match_operand:SI 0 "int_reg_operand" "") ;; bool out
391 (match_operand:AINT 1 "int_reg_operand" "") ;; val out
392 (match_operand:AINT 2 "memory_operand" "") ;; memory
393 (match_operand:AINT 3 "reg_or_short_operand" "") ;; expected
394 (match_operand:AINT 4 "int_reg_operand" "") ;; desired
2747a046
RH
395 (match_operand:SI 5 "const_int_operand" "") ;; is_weak
396 (match_operand:SI 6 "const_int_operand" "") ;; model succ
397 (match_operand:SI 7 "const_int_operand" "")] ;; model fail
a441dedb 398 ""
f565b0a1 399{
2747a046 400 rs6000_expand_atomic_compare_and_swap (operands);
f565b0a1 401 DONE;
9f0076e5 402})
f565b0a1 403
2747a046 404(define_expand "atomic_exchange<mode>"
4b02c962
MM
405 [(match_operand:AINT 0 "int_reg_operand" "") ;; output
406 (match_operand:AINT 1 "memory_operand" "") ;; memory
407 (match_operand:AINT 2 "int_reg_operand" "") ;; input
2747a046 408 (match_operand:SI 3 "const_int_operand" "")] ;; model
a441dedb 409 ""
f565b0a1 410{
2747a046 411 rs6000_expand_atomic_exchange (operands);
f565b0a1 412 DONE;
9f0076e5 413})
f565b0a1 414
2747a046 415(define_expand "atomic_<fetchop_name><mode>"
4b02c962
MM
416 [(match_operand:AINT 0 "memory_operand" "") ;; memory
417 (FETCHOP:AINT (match_dup 0)
418 (match_operand:AINT 1 "<fetchop_pred>" "")) ;; operand
2747a046 419 (match_operand:SI 2 "const_int_operand" "")] ;; model
a441dedb 420 ""
f565b0a1 421{
2747a046
RH
422 rs6000_expand_atomic_op (<CODE>, operands[0], operands[1],
423 NULL_RTX, NULL_RTX, operands[2]);
f565b0a1 424 DONE;
9f0076e5 425})
f565b0a1 426
2747a046 427(define_expand "atomic_nand<mode>"
4b02c962
MM
428 [(match_operand:AINT 0 "memory_operand" "") ;; memory
429 (match_operand:AINT 1 "int_reg_operand" "") ;; operand
2747a046 430 (match_operand:SI 2 "const_int_operand" "")] ;; model
a441dedb 431 ""
f565b0a1 432{
2747a046
RH
433 rs6000_expand_atomic_op (NOT, operands[0], operands[1],
434 NULL_RTX, NULL_RTX, operands[2]);
f565b0a1 435 DONE;
9f0076e5 436})
f565b0a1 437
2747a046 438(define_expand "atomic_fetch_<fetchop_name><mode>"
4b02c962
MM
439 [(match_operand:AINT 0 "int_reg_operand" "") ;; output
440 (match_operand:AINT 1 "memory_operand" "") ;; memory
441 (FETCHOP:AINT (match_dup 1)
442 (match_operand:AINT 2 "<fetchop_pred>" "")) ;; operand
2747a046 443 (match_operand:SI 3 "const_int_operand" "")] ;; model
a441dedb 444 ""
2747a046
RH
445{
446 rs6000_expand_atomic_op (<CODE>, operands[1], operands[2],
447 operands[0], NULL_RTX, operands[3]);
f565b0a1 448 DONE;
9f0076e5 449})
f565b0a1 450
2747a046 451(define_expand "atomic_fetch_nand<mode>"
4b02c962
MM
452 [(match_operand:AINT 0 "int_reg_operand" "") ;; output
453 (match_operand:AINT 1 "memory_operand" "") ;; memory
454 (match_operand:AINT 2 "int_reg_operand" "") ;; operand
2747a046 455 (match_operand:SI 3 "const_int_operand" "")] ;; model
a441dedb 456 ""
f565b0a1 457{
2747a046
RH
458 rs6000_expand_atomic_op (NOT, operands[1], operands[2],
459 operands[0], NULL_RTX, operands[3]);
460 DONE;
461})
f565b0a1 462
2747a046 463(define_expand "atomic_<fetchop_name>_fetch<mode>"
4b02c962
MM
464 [(match_operand:AINT 0 "int_reg_operand" "") ;; output
465 (match_operand:AINT 1 "memory_operand" "") ;; memory
466 (FETCHOP:AINT (match_dup 1)
467 (match_operand:AINT 2 "<fetchop_pred>" "")) ;; operand
2747a046 468 (match_operand:SI 3 "const_int_operand" "")] ;; model
a441dedb 469 ""
f565b0a1 470{
2747a046
RH
471 rs6000_expand_atomic_op (<CODE>, operands[1], operands[2],
472 NULL_RTX, operands[0], operands[3]);
f565b0a1 473 DONE;
9f0076e5
DE
474})
475
2747a046 476(define_expand "atomic_nand_fetch<mode>"
4b02c962
MM
477 [(match_operand:AINT 0 "int_reg_operand" "") ;; output
478 (match_operand:AINT 1 "memory_operand" "") ;; memory
479 (match_operand:AINT 2 "int_reg_operand" "") ;; operand
2747a046 480 (match_operand:SI 3 "const_int_operand" "")] ;; model
a441dedb 481 ""
f565b0a1 482{
2747a046
RH
483 rs6000_expand_atomic_op (NOT, operands[1], operands[2],
484 NULL_RTX, operands[0], operands[3]);
f565b0a1 485 DONE;
2747a046 486})