xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/rs6000/sync.md (revision 8ecbf5f02b752fcb7debe1a8fab1dc82602bc760)
1;; Machine description for PowerPC synchronization instructions.
2;; Copyright (C) 2005-2018 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 = memmodel_base (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 = memmodel_base (INTVAL (operands[2]));
148
149  if (is_mm_seq_cst (model))
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      if (!quad_address_p (XEXP (op1, 0), TImode, false))
161	{
162	  rtx old_addr = XEXP (op1, 0);
163	  rtx new_addr = force_reg (Pmode, old_addr);
164	  operands[1] = op1 = replace_equiv_address (op1, new_addr);
165	}
166
167      emit_insn (gen_load_quadpti (pti_reg, op1));
168
169      if (WORDS_BIG_ENDIAN)
170	emit_move_insn (op0, gen_lowpart (TImode, pti_reg));
171      else
172	{
173	  emit_move_insn (gen_lowpart (DImode, op0), gen_highpart (DImode, pti_reg));
174	  emit_move_insn (gen_highpart (DImode, op0), gen_lowpart (DImode, pti_reg));
175	}
176    }
177
178  switch (model)
179    {
180    case MEMMODEL_RELAXED:
181      break;
182    case MEMMODEL_CONSUME:
183    case MEMMODEL_ACQUIRE:
184    case MEMMODEL_SEQ_CST:
185      emit_insn (gen_loadsync_<mode> (operands[0]));
186      break;
187    default:
188      gcc_unreachable ();
189    }
190  DONE;
191})
192
193(define_insn "store_quadpti"
194  [(set (match_operand:PTI 0 "quad_memory_operand" "=wQ")
195	(unspec:PTI
196	 [(match_operand:PTI 1 "quad_int_reg_operand" "r")] UNSPEC_LSQ))]
197  "TARGET_SYNC_TI"
198  "stq %1,%0"
199  [(set_attr "type" "store")
200   (set_attr "length" "4")])
201
202(define_expand "atomic_store<mode>"
203  [(set (match_operand:AINT 0 "memory_operand")		;; memory
204	(match_operand:AINT 1 "register_operand"))	;; input
205   (use (match_operand:SI 2 "const_int_operand"))]	;; model
206  ""
207{
208  if (<MODE>mode == TImode && !TARGET_SYNC_TI)
209    FAIL;
210
211  enum memmodel model = memmodel_base (INTVAL (operands[2]));
212  switch (model)
213    {
214    case MEMMODEL_RELAXED:
215      break;
216    case MEMMODEL_RELEASE:
217      emit_insn (gen_lwsync ());
218      break;
219    case MEMMODEL_SEQ_CST:
220      emit_insn (gen_hwsync ());
221      break;
222    default:
223      gcc_unreachable ();
224    }
225  if (<MODE>mode != TImode)
226    emit_move_insn (operands[0], operands[1]);
227  else
228    {
229      rtx op0 = operands[0];
230      rtx op1 = operands[1];
231      rtx pti_reg = gen_reg_rtx (PTImode);
232
233      if (!quad_address_p (XEXP (op0, 0), TImode, false))
234	{
235	  rtx old_addr = XEXP (op0, 0);
236	  rtx new_addr = force_reg (Pmode, old_addr);
237	  operands[0] = op0 = replace_equiv_address (op0, new_addr);
238	}
239
240      if (WORDS_BIG_ENDIAN)
241	emit_move_insn (pti_reg, gen_lowpart (PTImode, op1));
242      else
243	{
244	  emit_move_insn (gen_lowpart (DImode, pti_reg), gen_highpart (DImode, op1));
245	  emit_move_insn (gen_highpart (DImode, pti_reg), gen_lowpart (DImode, op1));
246	}
247
248      emit_insn (gen_store_quadpti (gen_lowpart (PTImode, op0), pti_reg));
249    }
250
251  DONE;
252})
253
254;; Any supported integer mode that has atomic l<x>arx/st<x>cx. instrucitons
255;; other than the quad memory operations, which have special restrictions.
256;; Byte/halfword atomic instructions were added in ISA 2.06B, but were phased
257;; in and did not show up until power8.  TImode atomic lqarx/stqcx. require
258;; special handling due to even/odd register requirements.
259(define_mode_iterator ATOMIC [(QI "TARGET_SYNC_HI_QI")
260			      (HI "TARGET_SYNC_HI_QI")
261			      SI
262			      (DI "TARGET_POWERPC64")])
263
264(define_insn "load_locked<mode>"
265  [(set (match_operand:ATOMIC 0 "int_reg_operand" "=r")
266	(unspec_volatile:ATOMIC
267         [(match_operand:ATOMIC 1 "memory_operand" "Z")] UNSPECV_LL))]
268  ""
269  "<larx> %0,%y1"
270  [(set_attr "type" "load_l")])
271
272(define_insn "load_locked<QHI:mode>_si"
273  [(set (match_operand:SI 0 "int_reg_operand" "=r")
274	(unspec_volatile:SI
275	  [(match_operand:QHI 1 "memory_operand" "Z")] UNSPECV_LL))]
276  "TARGET_SYNC_HI_QI"
277  "<QHI:larx> %0,%y1"
278  [(set_attr "type" "load_l")])
279
280;; Use PTImode to get even/odd register pairs.
281;; Use a temporary register to force getting an even register for the
282;; lqarx/stqcrx. instructions.  Normal optimizations will eliminate this extra
283;; copy on big endian systems.
284
285;; On little endian systems where non-atomic quad word load/store instructions
286;; are not used, the address can be register+offset, so make sure the address
287;; is indexed or indirect before register allocation.
288
289(define_expand "load_lockedti"
290  [(use (match_operand:TI 0 "quad_int_reg_operand"))
291   (use (match_operand:TI 1 "memory_operand"))]
292  "TARGET_SYNC_TI"
293{
294  rtx op0 = operands[0];
295  rtx op1 = operands[1];
296  rtx pti = gen_reg_rtx (PTImode);
297
298  if (!indexed_or_indirect_operand (op1, TImode))
299    {
300      rtx old_addr = XEXP (op1, 0);
301      rtx new_addr = force_reg (Pmode, old_addr);
302      operands[1] = op1 = change_address (op1, TImode, new_addr);
303    }
304
305  emit_insn (gen_load_lockedpti (pti, op1));
306  if (WORDS_BIG_ENDIAN)
307    emit_move_insn (op0, gen_lowpart (TImode, pti));
308  else
309    {
310      emit_move_insn (gen_lowpart (DImode, op0), gen_highpart (DImode, pti));
311      emit_move_insn (gen_highpart (DImode, op0), gen_lowpart (DImode, pti));
312    }
313  DONE;
314})
315
316(define_insn "load_lockedpti"
317  [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r")
318	(unspec_volatile:PTI
319         [(match_operand:TI 1 "indexed_or_indirect_operand" "Z")] UNSPECV_LL))]
320  "TARGET_SYNC_TI
321   && !reg_mentioned_p (operands[0], operands[1])
322   && quad_int_reg_operand (operands[0], PTImode)"
323  "lqarx %0,%y1"
324  [(set_attr "type" "load_l")])
325
326(define_insn "store_conditional<mode>"
327  [(set (match_operand:CC 0 "cc_reg_operand" "=x")
328	(unspec_volatile:CC [(const_int 0)] UNSPECV_SC))
329   (set (match_operand:ATOMIC 1 "memory_operand" "=Z")
330	(match_operand:ATOMIC 2 "int_reg_operand" "r"))]
331  ""
332  "<stcx> %2,%y1"
333  [(set_attr "type" "store_c")])
334
335;; Use a temporary register to force getting an even register for the
336;; lqarx/stqcrx. instructions.  Normal optimizations will eliminate this extra
337;; copy on big endian systems.
338
339;; On little endian systems where non-atomic quad word load/store instructions
340;; are not used, the address can be register+offset, so make sure the address
341;; is indexed or indirect before register allocation.
342
343(define_expand "store_conditionalti"
344  [(use (match_operand:CC 0 "cc_reg_operand"))
345   (use (match_operand:TI 1 "memory_operand"))
346   (use (match_operand:TI 2 "quad_int_reg_operand"))]
347  "TARGET_SYNC_TI"
348{
349  rtx op0 = operands[0];
350  rtx op1 = operands[1];
351  rtx op2 = operands[2];
352  rtx addr = XEXP (op1, 0);
353  rtx pti_mem;
354  rtx pti_reg;
355
356  if (!indexed_or_indirect_operand (op1, TImode))
357    {
358      rtx new_addr = force_reg (Pmode, addr);
359      operands[1] = op1 = change_address (op1, TImode, new_addr);
360      addr = new_addr;
361    }
362
363  pti_mem = change_address (op1, PTImode, addr);
364  pti_reg = gen_reg_rtx (PTImode);
365
366  if (WORDS_BIG_ENDIAN)
367    emit_move_insn (pti_reg, gen_lowpart (PTImode, op2));
368  else
369    {
370      emit_move_insn (gen_lowpart (DImode, pti_reg), gen_highpart (DImode, op2));
371      emit_move_insn (gen_highpart (DImode, pti_reg), gen_lowpart (DImode, op2));
372    }
373
374  emit_insn (gen_store_conditionalpti (op0, pti_mem, pti_reg));
375  DONE;
376})
377
378(define_insn "store_conditionalpti"
379  [(set (match_operand:CC 0 "cc_reg_operand" "=x")
380	(unspec_volatile:CC [(const_int 0)] UNSPECV_SC))
381   (set (match_operand:PTI 1 "indexed_or_indirect_operand" "=Z")
382	(match_operand:PTI 2 "quad_int_reg_operand" "r"))]
383  "TARGET_SYNC_TI && quad_int_reg_operand (operands[2], PTImode)"
384  "stqcx. %2,%y1"
385  [(set_attr "type" "store_c")])
386
387(define_expand "atomic_compare_and_swap<mode>"
388  [(match_operand:SI 0 "int_reg_operand")		;; bool out
389   (match_operand:AINT 1 "int_reg_operand")		;; val out
390   (match_operand:AINT 2 "memory_operand")		;; memory
391   (match_operand:AINT 3 "reg_or_short_operand")	;; expected
392   (match_operand:AINT 4 "int_reg_operand")		;; desired
393   (match_operand:SI 5 "const_int_operand")		;; is_weak
394   (match_operand:SI 6 "const_int_operand")		;; model succ
395   (match_operand:SI 7 "const_int_operand")]		;; model fail
396  ""
397{
398  rs6000_expand_atomic_compare_and_swap (operands);
399  DONE;
400})
401
402(define_expand "atomic_exchange<mode>"
403  [(match_operand:AINT 0 "int_reg_operand")		;; output
404   (match_operand:AINT 1 "memory_operand")		;; memory
405   (match_operand:AINT 2 "int_reg_operand")		;; input
406   (match_operand:SI 3 "const_int_operand")]		;; model
407  ""
408{
409  rs6000_expand_atomic_exchange (operands);
410  DONE;
411})
412
413(define_expand "atomic_<fetchop_name><mode>"
414  [(match_operand:AINT 0 "memory_operand")		;; memory
415   (FETCHOP:AINT (match_dup 0)
416     (match_operand:AINT 1 "<fetchop_pred>"))		;; operand
417   (match_operand:SI 2 "const_int_operand")]		;; model
418  ""
419{
420  rs6000_expand_atomic_op (<CODE>, operands[0], operands[1],
421			   NULL_RTX, NULL_RTX, operands[2]);
422  DONE;
423})
424
425(define_expand "atomic_nand<mode>"
426  [(match_operand:AINT 0 "memory_operand")		;; memory
427   (match_operand:AINT 1 "int_reg_operand")		;; operand
428   (match_operand:SI 2 "const_int_operand")]		;; model
429  ""
430{
431  rs6000_expand_atomic_op (NOT, operands[0], operands[1],
432			   NULL_RTX, NULL_RTX, operands[2]);
433  DONE;
434})
435
436(define_expand "atomic_fetch_<fetchop_name><mode>"
437  [(match_operand:AINT 0 "int_reg_operand")		;; output
438   (match_operand:AINT 1 "memory_operand")		;; memory
439   (FETCHOP:AINT (match_dup 1)
440     (match_operand:AINT 2 "<fetchop_pred>"))		;; operand
441   (match_operand:SI 3 "const_int_operand")]		;; model
442  ""
443{
444  rs6000_expand_atomic_op (<CODE>, operands[1], operands[2],
445			   operands[0], NULL_RTX, operands[3]);
446  DONE;
447})
448
449(define_expand "atomic_fetch_nand<mode>"
450  [(match_operand:AINT 0 "int_reg_operand")		;; output
451   (match_operand:AINT 1 "memory_operand")		;; memory
452   (match_operand:AINT 2 "int_reg_operand")		;; operand
453   (match_operand:SI 3 "const_int_operand")]		;; model
454  ""
455{
456  rs6000_expand_atomic_op (NOT, operands[1], operands[2],
457			   operands[0], NULL_RTX, operands[3]);
458  DONE;
459})
460
461(define_expand "atomic_<fetchop_name>_fetch<mode>"
462  [(match_operand:AINT 0 "int_reg_operand")		;; output
463   (match_operand:AINT 1 "memory_operand")		;; memory
464   (FETCHOP:AINT (match_dup 1)
465     (match_operand:AINT 2 "<fetchop_pred>"))		;; operand
466   (match_operand:SI 3 "const_int_operand")]		;; model
467  ""
468{
469  rs6000_expand_atomic_op (<CODE>, operands[1], operands[2],
470			   NULL_RTX, operands[0], operands[3]);
471  DONE;
472})
473
474(define_expand "atomic_nand_fetch<mode>"
475  [(match_operand:AINT 0 "int_reg_operand")		;; output
476   (match_operand:AINT 1 "memory_operand")		;; memory
477   (match_operand:AINT 2 "int_reg_operand")		;; operand
478   (match_operand:SI 3 "const_int_operand")]		;; model
479  ""
480{
481  rs6000_expand_atomic_op (NOT, operands[1], operands[2],
482			   NULL_RTX, operands[0], operands[3]);
483  DONE;
484})
485