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