xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/rs6000/sync.md (revision 63aea4bd5b445e491ff0389fe27ec78b3099dba3)
1;; Machine description for PowerPC synchronization instructions.
2;; Copyright (C) 2005-2014 Free Software Foundation, Inc.
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
9;; by the Free Software Foundation; either version 3, or (at your
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
18;; along with GCC; see the file COPYING3.  If not see
19;; <http://www.gnu.org/licenses/>.
20
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.")])
32
33(define_code_iterator FETCHOP [plus minus ior xor and])
34(define_code_attr fetchop_name
35  [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")])
36(define_code_attr fetchop_pred
37  [(plus "add_operand") (minus "int_reg_operand")
38   (ior "logical_operand") (xor "logical_operand") (and "and_operand")])
39
40(define_expand "mem_thread_fence"
41  [(match_operand:SI 0 "const_int_operand" "")]		;; model
42  ""
43{
44  enum memmodel model = (enum memmodel) INTVAL (operands[0]);
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"
65  [(set (match_dup 0)
66	(unspec:BLK [(match_dup 0)] UNSPEC_SYNC))]
67  ""
68{
69  operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
70  MEM_VOLATILE_P (operands[0]) = 1;
71})
72
73(define_insn "*hwsync"
74  [(set (match_operand:BLK 0 "" "")
75	(unspec:BLK [(match_dup 0)] UNSPEC_SYNC))]
76  ""
77  "sync"
78  [(set_attr "type" "sync")])
79
80(define_expand "lwsync"
81  [(set (match_dup 0)
82	(unspec:BLK [(match_dup 0)] UNSPEC_LWSYNC))]
83  ""
84{
85  operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
86  MEM_VOLATILE_P (operands[0]) = 1;
87})
88
89(define_insn "*lwsync"
90  [(set (match_operand:BLK 0 "" "")
91	(unspec:BLK [(match_dup 0)] UNSPEC_LWSYNC))]
92  ""
93{
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")])
103
104(define_insn "isync"
105  [(unspec_volatile:BLK [(const_int 0)] UNSPECV_ISYNC)]
106  ""
107  "isync"
108  [(set_attr "type" "isync")])
109
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
117;; The control dependency used for load dependency described
118;; in B.2.3 of the Power ISA 2.06B.
119(define_insn "loadsync_<mode>"
120  [(unspec_volatile:BLK [(match_operand:AINT 0 "register_operand" "r")]
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
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
138(define_expand "atomic_load<mode>"
139  [(set (match_operand:AINT 0 "register_operand" "")		;; output
140	(match_operand:AINT 1 "memory_operand" ""))		;; memory
141   (use (match_operand:SI 2 "const_int_operand" ""))]		;; model
142  ""
143{
144  if (<MODE>mode == TImode && !TARGET_SYNC_TI)
145    FAIL;
146
147  enum memmodel model = (enum memmodel) INTVAL (operands[2]);
148
149  if (model == MEMMODEL_SEQ_CST)
150    emit_insn (gen_hwsync ());
151
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      /* For 4.8 we need to do explicit dword copies, even in big endian mode,
171	 unless we are using the LRA register allocator. The 4.9 register
172	 allocator is smart enough to assign an even/odd pair. */
173      if (WORDS_BIG_ENDIAN && rs6000_lra_flag)
174	emit_move_insn (op0, gen_lowpart (TImode, pti_reg));
175      else
176	{
177	  rtx op0_lo = gen_lowpart (DImode, op0);
178	  rtx op0_hi = gen_highpart (DImode, op0);
179	  rtx pti_lo = gen_lowpart (DImode, pti_reg);
180	  rtx pti_hi = gen_highpart (DImode, pti_reg);
181
182	  emit_insn (gen_rtx_CLOBBER (VOIDmode, op0));
183	  if (WORDS_BIG_ENDIAN)
184	    {
185	      emit_move_insn (op0_hi, pti_hi);
186	      emit_move_insn (op0_lo, pti_lo);
187	    }
188	  else
189	    {
190	      emit_move_insn (op0_hi, pti_lo);
191	      emit_move_insn (op0_lo, pti_hi);
192	    }
193	}
194    }
195
196  switch (model)
197    {
198    case MEMMODEL_RELAXED:
199      break;
200    case MEMMODEL_CONSUME:
201    case MEMMODEL_ACQUIRE:
202    case MEMMODEL_SEQ_CST:
203      emit_insn (gen_loadsync_<mode> (operands[0]));
204      break;
205    default:
206      gcc_unreachable ();
207    }
208  DONE;
209})
210
211(define_insn "store_quadpti"
212  [(set (match_operand:PTI 0 "quad_memory_operand" "=wQ")
213	(unspec:PTI
214	 [(match_operand:PTI 1 "quad_int_reg_operand" "r")] UNSPEC_LSQ))]
215  "TARGET_SYNC_TI"
216  "stq %1,%0"
217  [(set_attr "type" "store")
218   (set_attr "length" "4")])
219
220(define_expand "atomic_store<mode>"
221  [(set (match_operand:AINT 0 "memory_operand" "")		;; memory
222	(match_operand:AINT 1 "register_operand" ""))		;; input
223   (use (match_operand:SI 2 "const_int_operand" ""))]		;; model
224  ""
225{
226  if (<MODE>mode == TImode && !TARGET_SYNC_TI)
227    FAIL;
228
229  enum memmodel model = (enum memmodel) INTVAL (operands[2]);
230  switch (model)
231    {
232    case MEMMODEL_RELAXED:
233      break;
234    case MEMMODEL_RELEASE:
235      emit_insn (gen_lwsync ());
236      break;
237    case MEMMODEL_SEQ_CST:
238      emit_insn (gen_hwsync ());
239      break;
240    default:
241      gcc_unreachable ();
242    }
243  if (<MODE>mode != TImode)
244    emit_move_insn (operands[0], operands[1]);
245  else
246    {
247      rtx op0 = operands[0];
248      rtx op1 = operands[1];
249      rtx pti_reg = gen_reg_rtx (PTImode);
250
251      // Can't have indexed address for 'stq'
252      if (indexed_address (XEXP (op0, 0), TImode))
253	{
254	  rtx old_addr = XEXP (op0, 0);
255	  rtx new_addr = force_reg (Pmode, old_addr);
256	  operands[0] = op0 = replace_equiv_address (op0, new_addr);
257	}
258
259      /* For 4.8 we need to do explicit dword copies, even in big endian mode,
260	 unless we are using the LRA register allocator. The 4.9 register
261	 allocator is smart enough to assign an even/odd pair. */
262      if (WORDS_BIG_ENDIAN && rs6000_lra_flag)
263	emit_move_insn (pti_reg, gen_lowpart (PTImode, op1));
264      else
265	{
266	  rtx op1_lo = gen_lowpart (DImode, op1);
267	  rtx op1_hi = gen_highpart (DImode, op1);
268	  rtx pti_lo = gen_lowpart (DImode, pti_reg);
269	  rtx pti_hi = gen_highpart (DImode, pti_reg);
270
271	  emit_insn (gen_rtx_CLOBBER (VOIDmode, pti_reg));
272	  if (WORDS_BIG_ENDIAN)
273	    {
274	      emit_move_insn (pti_hi, op1_hi);
275	      emit_move_insn (pti_lo, op1_lo);
276	    }
277	  else
278	    {
279	      emit_move_insn (pti_hi, op1_lo);
280	      emit_move_insn (pti_lo, op1_hi);
281	    }
282	}
283
284      emit_insn (gen_store_quadpti (gen_lowpart (PTImode, op0), pti_reg));
285    }
286
287  DONE;
288})
289
290;; Any supported integer mode that has atomic l<x>arx/st<x>cx. instrucitons
291;; other than the quad memory operations, which have special restrictions.
292;; Byte/halfword atomic instructions were added in ISA 2.06B, but were phased
293;; in and did not show up until power8.  TImode atomic lqarx/stqcx. require
294;; special handling due to even/odd register requirements.
295(define_mode_iterator ATOMIC [(QI "TARGET_SYNC_HI_QI")
296			      (HI "TARGET_SYNC_HI_QI")
297			      SI
298			      (DI "TARGET_POWERPC64")])
299
300(define_insn "load_locked<mode>"
301  [(set (match_operand:ATOMIC 0 "int_reg_operand" "=r")
302	(unspec_volatile:ATOMIC
303         [(match_operand:ATOMIC 1 "memory_operand" "Z")] UNSPECV_LL))]
304  ""
305  "<larx> %0,%y1"
306  [(set_attr "type" "load_l")])
307
308(define_insn "load_locked<QHI:mode>_si"
309  [(set (match_operand:SI 0 "int_reg_operand" "=r")
310	(unspec_volatile:SI
311	  [(match_operand:QHI 1 "memory_operand" "Z")] UNSPECV_LL))]
312  "TARGET_SYNC_HI_QI"
313  "<QHI:larx> %0,%y1"
314  [(set_attr "type" "load_l")])
315
316;; Use PTImode to get even/odd register pairs.
317
318;; Use a temporary register to force getting an even register for the
319;; lqarx/stqcrx. instructions.  Under AT 7.0, we need use an explicit copy,
320;; even in big endian mode, unless we are using the LRA register allocator.  In
321;; GCC 4.9, the register allocator is smart enough to assign a even/odd
322;; register pair.
323
324;; On little endian systems where non-atomic quad word load/store instructions
325;; are not used, the address can be register+offset, so make sure the address
326;; is indexed or indirect before register allocation.
327
328(define_expand "load_lockedti"
329  [(use (match_operand:TI 0 "quad_int_reg_operand" ""))
330   (use (match_operand:TI 1 "memory_operand" ""))]
331  "TARGET_SYNC_TI"
332{
333  rtx op0 = operands[0];
334  rtx op1 = operands[1];
335  rtx pti = gen_reg_rtx (PTImode);
336
337  if (!indexed_or_indirect_operand (op1, TImode))
338    {
339      rtx old_addr = XEXP (op1, 0);
340      rtx new_addr = force_reg (Pmode, old_addr);
341      operands[1] = op1 = change_address (op1, TImode, new_addr);
342    }
343
344  emit_insn (gen_load_lockedpti (pti, op1));
345  if (WORDS_BIG_ENDIAN && rs6000_lra_flag)
346    emit_move_insn (op0, gen_lowpart (TImode, pti));
347  else
348    {
349      rtx op0_lo = gen_lowpart (DImode, op0);
350      rtx op0_hi = gen_highpart (DImode, op0);
351      rtx pti_lo = gen_lowpart (DImode, pti);
352      rtx pti_hi = gen_highpart (DImode, pti);
353
354      emit_insn (gen_rtx_CLOBBER (VOIDmode, op0));
355      if (WORDS_BIG_ENDIAN)
356	{
357	  emit_move_insn (op0_hi, pti_hi);
358	  emit_move_insn (op0_lo, pti_lo);
359	}
360      else
361	{
362	  emit_move_insn (op0_hi, pti_lo);
363	  emit_move_insn (op0_lo, pti_hi);
364	}
365    }
366  DONE;
367})
368
369(define_insn "load_lockedpti"
370  [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r")
371	(unspec_volatile:PTI
372         [(match_operand:TI 1 "indexed_or_indirect_operand" "Z")] UNSPECV_LL))]
373  "TARGET_SYNC_TI
374   && !reg_mentioned_p (operands[0], operands[1])
375   && quad_int_reg_operand (operands[0], PTImode)"
376  "lqarx %0,%y1"
377  [(set_attr "type" "load_l")])
378
379(define_insn "store_conditional<mode>"
380  [(set (match_operand:CC 0 "cc_reg_operand" "=x")
381	(unspec_volatile:CC [(const_int 0)] UNSPECV_SC))
382   (set (match_operand:ATOMIC 1 "memory_operand" "=Z")
383	(match_operand:ATOMIC 2 "int_reg_operand" "r"))]
384  ""
385  "<stcx> %2,%y1"
386  [(set_attr "type" "store_c")])
387
388;; Use a temporary register to force getting an even register for the
389;; lqarx/stqcrx. instructions.  Under AT 7.0, we need use an explicit copy,
390;; even in big endian mode.  In GCC 4.9, the register allocator is smart enough
391;; to assign a even/odd register pair.
392
393;; On little endian systems where non-atomic quad word load/store instructions
394;; are not used, the address can be register+offset, so make sure the address
395;; is indexed or indirect before register allocation.
396
397(define_expand "store_conditionalti"
398  [(use (match_operand:CC 0 "cc_reg_operand" ""))
399   (use (match_operand:TI 1 "memory_operand" ""))
400   (use (match_operand:TI 2 "quad_int_reg_operand" ""))]
401  "TARGET_SYNC_TI"
402{
403  rtx op0 = operands[0];
404  rtx op1 = operands[1];
405  rtx op2 = operands[2];
406  rtx addr = XEXP (op1, 0);
407  rtx pti_mem;
408  rtx pti_reg;
409
410  if (!indexed_or_indirect_operand (op1, TImode))
411    {
412      rtx new_addr = force_reg (Pmode, addr);
413      operands[1] = op1 = change_address (op1, TImode, new_addr);
414      addr = new_addr;
415    }
416
417  pti_mem = change_address (op1, PTImode, addr);
418  pti_reg = gen_reg_rtx (PTImode);
419
420  if (WORDS_BIG_ENDIAN && rs6000_lra_flag)
421    emit_move_insn (pti_reg, gen_lowpart (PTImode, op2));
422  else
423    {
424      rtx op2_lo = gen_lowpart (DImode, op2);
425      rtx op2_hi = gen_highpart (DImode, op2);
426      rtx pti_lo = gen_lowpart (DImode, pti_reg);
427      rtx pti_hi = gen_highpart (DImode, pti_reg);
428
429      emit_insn (gen_rtx_CLOBBER (VOIDmode, op0));
430      if (WORDS_BIG_ENDIAN)
431	{
432	  emit_move_insn (pti_hi, op2_hi);
433	  emit_move_insn (pti_lo, op2_lo);
434	}
435      else
436	{
437	  emit_move_insn (pti_hi, op2_lo);
438	  emit_move_insn (pti_lo, op2_hi);
439	}
440    }
441
442  emit_insn (gen_store_conditionalpti (op0, pti_mem, pti_reg));
443  DONE;
444})
445
446(define_insn "store_conditionalpti"
447  [(set (match_operand:CC 0 "cc_reg_operand" "=x")
448	(unspec_volatile:CC [(const_int 0)] UNSPECV_SC))
449   (set (match_operand:PTI 1 "indexed_or_indirect_operand" "=Z")
450	(match_operand:PTI 2 "quad_int_reg_operand" "r"))]
451  "TARGET_SYNC_TI && quad_int_reg_operand (operands[2], PTImode)"
452  "stqcx. %2,%y1"
453  [(set_attr "type" "store_c")])
454
455(define_expand "atomic_compare_and_swap<mode>"
456  [(match_operand:SI 0 "int_reg_operand" "")		;; bool out
457   (match_operand:AINT 1 "int_reg_operand" "")		;; val out
458   (match_operand:AINT 2 "memory_operand" "")		;; memory
459   (match_operand:AINT 3 "reg_or_short_operand" "")	;; expected
460   (match_operand:AINT 4 "int_reg_operand" "")		;; desired
461   (match_operand:SI 5 "const_int_operand" "")		;; is_weak
462   (match_operand:SI 6 "const_int_operand" "")		;; model succ
463   (match_operand:SI 7 "const_int_operand" "")]		;; model fail
464  ""
465{
466  rs6000_expand_atomic_compare_and_swap (operands);
467  DONE;
468})
469
470(define_expand "atomic_exchange<mode>"
471  [(match_operand:AINT 0 "int_reg_operand" "")		;; output
472   (match_operand:AINT 1 "memory_operand" "")		;; memory
473   (match_operand:AINT 2 "int_reg_operand" "")		;; input
474   (match_operand:SI 3 "const_int_operand" "")]		;; model
475  ""
476{
477  rs6000_expand_atomic_exchange (operands);
478  DONE;
479})
480
481(define_expand "atomic_<fetchop_name><mode>"
482  [(match_operand:AINT 0 "memory_operand" "")		;; memory
483   (FETCHOP:AINT (match_dup 0)
484     (match_operand:AINT 1 "<fetchop_pred>" ""))	;; operand
485   (match_operand:SI 2 "const_int_operand" "")]		;; model
486  ""
487{
488  rs6000_expand_atomic_op (<CODE>, operands[0], operands[1],
489			   NULL_RTX, NULL_RTX, operands[2]);
490  DONE;
491})
492
493(define_expand "atomic_nand<mode>"
494  [(match_operand:AINT 0 "memory_operand" "")		;; memory
495   (match_operand:AINT 1 "int_reg_operand" "")		;; operand
496   (match_operand:SI 2 "const_int_operand" "")]		;; model
497  ""
498{
499  rs6000_expand_atomic_op (NOT, operands[0], operands[1],
500			   NULL_RTX, NULL_RTX, operands[2]);
501  DONE;
502})
503
504(define_expand "atomic_fetch_<fetchop_name><mode>"
505  [(match_operand:AINT 0 "int_reg_operand" "")		;; output
506   (match_operand:AINT 1 "memory_operand" "")		;; memory
507   (FETCHOP:AINT (match_dup 1)
508     (match_operand:AINT 2 "<fetchop_pred>" ""))	;; operand
509   (match_operand:SI 3 "const_int_operand" "")]		;; model
510  ""
511{
512  rs6000_expand_atomic_op (<CODE>, operands[1], operands[2],
513			   operands[0], NULL_RTX, operands[3]);
514  DONE;
515})
516
517(define_expand "atomic_fetch_nand<mode>"
518  [(match_operand:AINT 0 "int_reg_operand" "")		;; output
519   (match_operand:AINT 1 "memory_operand" "")		;; memory
520   (match_operand:AINT 2 "int_reg_operand" "")		;; operand
521   (match_operand:SI 3 "const_int_operand" "")]		;; model
522  ""
523{
524  rs6000_expand_atomic_op (NOT, operands[1], operands[2],
525			   operands[0], NULL_RTX, operands[3]);
526  DONE;
527})
528
529(define_expand "atomic_<fetchop_name>_fetch<mode>"
530  [(match_operand:AINT 0 "int_reg_operand" "")		;; output
531   (match_operand:AINT 1 "memory_operand" "")		;; memory
532   (FETCHOP:AINT (match_dup 1)
533     (match_operand:AINT 2 "<fetchop_pred>" ""))	;; operand
534   (match_operand:SI 3 "const_int_operand" "")]		;; model
535  ""
536{
537  rs6000_expand_atomic_op (<CODE>, operands[1], operands[2],
538			   NULL_RTX, operands[0], operands[3]);
539  DONE;
540})
541
542(define_expand "atomic_nand_fetch<mode>"
543  [(match_operand:AINT 0 "int_reg_operand" "")		;; output
544   (match_operand:AINT 1 "memory_operand" "")		;; memory
545   (match_operand:AINT 2 "int_reg_operand" "")		;; operand
546   (match_operand:SI 3 "const_int_operand" "")]		;; model
547  ""
548{
549  rs6000_expand_atomic_op (NOT, operands[1], operands[2],
550			   NULL_RTX, operands[0], operands[3]);
551  DONE;
552})
553