Fix Ada runtime library breakage on Solaris
[official-gcc.git] / gcc / config / rs6000 / sync.md
blob425eff855d20891c1f1479bdda488978c297615b
1 ;; Machine description for PowerPC synchronization instructions.
2 ;; Copyright (C) 2005-2024 Free Software Foundation, Inc.
3 ;; Contributed by Geoffrey Keating.
5 ;; This file is part of GCC.
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.
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.
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/>.
21 (define_mode_attr larx [(QI "lbarx")
22                         (HI "lharx")
23                         (SI "lwarx")
24                         (DI "ldarx")
25                         (TI "lqarx")])
27 (define_mode_attr stcx [(QI "stbcx.")
28                         (HI "sthcx.")
29                         (SI "stwcx.")
30                         (DI "stdcx.")
31                         (TI "stqcx.")])
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")])
40 (define_expand "mem_thread_fence"
41   [(match_operand:SI 0 "const_int_operand")]            ;; model
42   ""
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;
64 (define_expand "hwsync"
65   [(set (match_dup 0)
66         (unspec:BLK [(match_dup 0)] UNSPEC_SYNC))]
67   ""
69   operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
70   MEM_VOLATILE_P (operands[0]) = 1;
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")])
80 (define_expand "lwsync"
81   [(set (match_dup 0)
82         (unspec:BLK [(match_dup 0)] UNSPEC_LWSYNC))]
83   ""
85   operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
86   MEM_VOLATILE_P (operands[0]) = 1;
89 (define_insn "*lwsync"
90   [(set (match_operand:BLK 0 "" "")
91         (unspec:BLK [(match_dup 0)] UNSPEC_LWSYNC))]
92   ""
94   if (TARGET_NO_LWSYNC)
95     return "sync";
96   else
97     return "lwsync";
99   [(set_attr "type" "sync")])
101 (define_insn "isync"
102   [(unspec_volatile:BLK [(const_int 0)] UNSPECV_ISYNC)]
103   ""
104   "isync"
105   [(set_attr "type" "isync")])
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")])
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")])
125 ;; If TARGET_PREFIXED, always use plq rather than lq.
126 (define_insn "load_quadpti"
127   [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r")
128         (unspec:PTI
129          [(match_operand:TI 1 "quad_memory_operand" "wQ")] UNSPEC_LSQ))]
130   "TARGET_SYNC_TI
131    && !reg_mentioned_p (operands[0], operands[1])"
132   "lq %0,%1"
133   [(set_attr "type" "load")
134    (set_attr "size" "128")
135    (set (attr "prefixed") (if_then_else (match_test "TARGET_PREFIXED")
136                                         (const_string "yes")
137                                         (const_string "no")))])
139 ;; Pattern load_quadpti will always use plq for atomic TImode if
140 ;; TARGET_PREFIXED.  It has the correct doubleword ordering on either LE
141 ;; or BE, so we can just move the result into the output register and
142 ;; do not need to do the doubleword swap for LE.  Also this avoids any
143 ;; confusion about whether the lq vs plq might be used based on whether
144 ;; op1 has PC-relative addressing.  We could potentially allow BE to
145 ;; use lq because it doesn't have the doubleword ordering problem.
146 (define_expand "atomic_load<mode>"
147   [(set (match_operand:AINT 0 "register_operand")               ;; output
148         (match_operand:AINT 1 "memory_operand"))                ;; memory
149    (use (match_operand:SI 2 "const_int_operand"))]              ;; model
150   ""
152   if (<MODE>mode == TImode && !TARGET_SYNC_TI)
153     FAIL;
155   enum memmodel model = memmodel_base (INTVAL (operands[2]));
157   if (is_mm_seq_cst (model))
158     emit_insn (gen_hwsync ());
160   if (<MODE>mode != TImode)
161     emit_move_insn (operands[0], operands[1]);
162   else
163     {
164       rtx op0 = operands[0];
165       rtx op1 = operands[1];
166       rtx pti_reg = gen_reg_rtx (PTImode);
168       if (!quad_address_p (XEXP (op1, 0), TImode, false))
169         {
170           rtx old_addr = XEXP (op1, 0);
171           rtx new_addr = force_reg (Pmode, old_addr);
172           operands[1] = op1 = replace_equiv_address (op1, new_addr);
173         }
175       emit_insn (gen_load_quadpti (pti_reg, op1));
177       if (WORDS_BIG_ENDIAN || TARGET_PREFIXED)
178         emit_move_insn (op0, gen_lowpart (TImode, pti_reg));
179       else
180         {
181           emit_move_insn (gen_lowpart (DImode, op0), gen_highpart (DImode, pti_reg));
182           emit_move_insn (gen_highpart (DImode, op0), gen_lowpart (DImode, pti_reg));
183         }
184     }
186   switch (model)
187     {
188     case MEMMODEL_RELAXED:
189       break;
190     case MEMMODEL_CONSUME:
191     case MEMMODEL_ACQUIRE:
192     case MEMMODEL_SEQ_CST:
193       emit_insn (gen_loadsync_<mode> (operands[0]));
194       break;
195     default:
196       gcc_unreachable ();
197     }
198   DONE;
201 ;; If TARGET_PREFIXED, always use pstq rather than stq.
202 (define_insn "store_quadpti"
203   [(set (match_operand:PTI 0 "quad_memory_operand" "=wQ")
204         (unspec:PTI
205          [(match_operand:PTI 1 "quad_int_reg_operand" "r")] UNSPEC_LSQ))]
206   "TARGET_SYNC_TI"
207   "stq %1,%0"
208   [(set_attr "type" "store")
209    (set_attr "size" "128")
210    (set (attr "prefixed") (if_then_else (match_test "TARGET_PREFIXED")
211                                         (const_string "yes")
212                                         (const_string "no")))])
214 ;; Pattern store_quadpti will always use pstq if TARGET_PREFIXED,
215 ;; so the doubleword swap is never needed in that case.
216 (define_expand "atomic_store<mode>"
217   [(set (match_operand:AINT 0 "memory_operand")         ;; memory
218         (match_operand:AINT 1 "register_operand"))      ;; input
219    (use (match_operand:SI 2 "const_int_operand"))]      ;; model
220   ""
222   if (<MODE>mode == TImode && !TARGET_SYNC_TI)
223     FAIL;
225   enum memmodel model = memmodel_base (INTVAL (operands[2]));
226   switch (model)
227     {
228     case MEMMODEL_RELAXED:
229       break;
230     case MEMMODEL_RELEASE:
231       emit_insn (gen_lwsync ());
232       break;
233     case MEMMODEL_SEQ_CST:
234       emit_insn (gen_hwsync ());
235       break;
236     default:
237       gcc_unreachable ();
238     }
239   if (<MODE>mode != TImode)
240     emit_move_insn (operands[0], operands[1]);
241   else
242     {
243       rtx op0 = operands[0];
244       rtx op1 = operands[1];
245       rtx pti_reg = gen_reg_rtx (PTImode);
247       if (!quad_address_p (XEXP (op0, 0), TImode, false))
248         {
249           rtx old_addr = XEXP (op0, 0);
250           rtx new_addr = force_reg (Pmode, old_addr);
251           operands[0] = op0 = replace_equiv_address (op0, new_addr);
252         }
254       if (WORDS_BIG_ENDIAN || TARGET_PREFIXED)
255         emit_move_insn (pti_reg, gen_lowpart (PTImode, op1));
256       else
257         {
258           emit_move_insn (gen_lowpart (DImode, pti_reg), gen_highpart (DImode, op1));
259           emit_move_insn (gen_highpart (DImode, pti_reg), gen_lowpart (DImode, op1));
260         }
262       emit_insn (gen_store_quadpti (gen_lowpart (PTImode, op0), pti_reg));
263     }
265   DONE;
268 ;; Any supported integer mode that has atomic l<x>arx/st<x>cx. instrucitons
269 ;; other than the quad memory operations, which have special restrictions.
270 ;; Byte/halfword atomic instructions were added in ISA 2.06B, but were phased
271 ;; in and did not show up until power8.  TImode atomic lqarx/stqcx. require
272 ;; special handling due to even/odd register requirements.
273 (define_mode_iterator ATOMIC [(QI "TARGET_SYNC_HI_QI")
274                               (HI "TARGET_SYNC_HI_QI")
275                               SI
276                               (DI "TARGET_POWERPC64")])
278 (define_insn "load_locked<mode>"
279   [(set (match_operand:ATOMIC 0 "int_reg_operand" "=r")
280         (unspec_volatile:ATOMIC
281          [(match_operand:ATOMIC 1 "memory_operand" "Z")] UNSPECV_LL))]
282   ""
283   "<larx> %0,%y1"
284   [(set_attr "type" "load_l")])
286 (define_insn "load_locked<QHI:mode>_si"
287   [(set (match_operand:SI 0 "int_reg_operand" "=r")
288         (unspec_volatile:SI
289           [(match_operand:QHI 1 "memory_operand" "Z")] UNSPECV_LL))]
290   "TARGET_SYNC_HI_QI"
291   "<QHI:larx> %0,%y1"
292   [(set_attr "type" "load_l")])
294 ;; Use PTImode to get even/odd register pairs.
295 ;; Use a temporary register to force getting an even register for the
296 ;; lqarx/stqcrx. instructions.  Normal optimizations will eliminate this extra
297 ;; copy on big endian systems.
299 ;; On little endian systems where non-atomic quad word load/store instructions
300 ;; are not used, the address can be register+offset, so make sure the address
301 ;; is indexed or indirect before register allocation.
303 (define_expand "load_lockedti"
304   [(use (match_operand:TI 0 "quad_int_reg_operand"))
305    (use (match_operand:TI 1 "memory_operand"))]
306   "TARGET_SYNC_TI"
308   rtx op0 = operands[0];
309   rtx op1 = operands[1];
310   rtx pti = gen_reg_rtx (PTImode);
312   if (!indexed_or_indirect_operand (op1, TImode))
313     {
314       rtx old_addr = XEXP (op1, 0);
315       rtx new_addr = force_reg (Pmode, old_addr);
316       operands[1] = op1 = change_address (op1, TImode, new_addr);
317     }
319   emit_insn (gen_load_lockedpti (pti, op1));
320   if (WORDS_BIG_ENDIAN)
321     emit_move_insn (op0, gen_lowpart (TImode, pti));
322   else
323     {
324       emit_move_insn (gen_lowpart (DImode, op0), gen_highpart (DImode, pti));
325       emit_move_insn (gen_highpart (DImode, op0), gen_lowpart (DImode, pti));
326     }
327   DONE;
330 (define_insn "load_lockedpti"
331   [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r")
332         (unspec_volatile:PTI
333          [(match_operand:TI 1 "indexed_or_indirect_operand" "Z")] UNSPECV_LL))]
334   "TARGET_SYNC_TI
335    && !reg_mentioned_p (operands[0], operands[1])
336    && quad_int_reg_operand (operands[0], PTImode)"
337   "lqarx %0,%y1"
338   [(set_attr "type" "load_l")
339    (set_attr "size" "128")])
341 (define_insn "store_conditional<mode>"
342   [(set (match_operand:CC 0 "cc_reg_operand" "=x")
343         (unspec_volatile:CC [(const_int 0)] UNSPECV_SC))
344    (set (match_operand:ATOMIC 1 "memory_operand" "=Z")
345         (match_operand:ATOMIC 2 "int_reg_operand" "r"))]
346   ""
347   "<stcx> %2,%y1"
348   [(set_attr "type" "store_c")])
350 ;; Use a temporary register to force getting an even register for the
351 ;; lqarx/stqcrx. instructions.  Normal optimizations will eliminate this extra
352 ;; copy on big endian systems.
354 ;; On little endian systems where non-atomic quad word load/store instructions
355 ;; are not used, the address can be register+offset, so make sure the address
356 ;; is indexed or indirect before register allocation.
358 (define_expand "store_conditionalti"
359   [(use (match_operand:CC 0 "cc_reg_operand"))
360    (use (match_operand:TI 1 "memory_operand"))
361    (use (match_operand:TI 2 "quad_int_reg_operand"))]
362   "TARGET_SYNC_TI"
364   rtx op0 = operands[0];
365   rtx op1 = operands[1];
366   rtx op2 = operands[2];
367   rtx addr = XEXP (op1, 0);
368   rtx pti_mem;
369   rtx pti_reg;
371   if (!indexed_or_indirect_operand (op1, TImode))
372     {
373       rtx new_addr = force_reg (Pmode, addr);
374       operands[1] = op1 = change_address (op1, TImode, new_addr);
375       addr = new_addr;
376     }
378   pti_mem = change_address (op1, PTImode, addr);
379   pti_reg = gen_reg_rtx (PTImode);
381   if (WORDS_BIG_ENDIAN)
382     emit_move_insn (pti_reg, gen_lowpart (PTImode, op2));
383   else
384     {
385       emit_move_insn (gen_lowpart (DImode, pti_reg), gen_highpart (DImode, op2));
386       emit_move_insn (gen_highpart (DImode, pti_reg), gen_lowpart (DImode, op2));
387     }
389   emit_insn (gen_store_conditionalpti (op0, pti_mem, pti_reg));
390   DONE;
393 (define_insn "store_conditionalpti"
394   [(set (match_operand:CC 0 "cc_reg_operand" "=x")
395         (unspec_volatile:CC [(const_int 0)] UNSPECV_SC))
396    (set (match_operand:PTI 1 "indexed_or_indirect_operand" "=Z")
397         (match_operand:PTI 2 "quad_int_reg_operand" "r"))]
398   "TARGET_SYNC_TI && quad_int_reg_operand (operands[2], PTImode)"
399   "stqcx. %2,%y1"
400   [(set_attr "type" "store_c")
401    (set_attr "size" "128")])
403 (define_expand "atomic_compare_and_swap<mode>"
404   [(match_operand:SI 0 "int_reg_operand")               ;; bool out
405    (match_operand:AINT 1 "int_reg_operand")             ;; val out
406    (match_operand:AINT 2 "memory_operand")              ;; memory
407    (match_operand:AINT 3 "reg_or_short_operand")        ;; expected
408    (match_operand:AINT 4 "int_reg_operand")             ;; desired
409    (match_operand:SI 5 "const_int_operand")             ;; is_weak
410    (match_operand:SI 6 "const_int_operand")             ;; model succ
411    (match_operand:SI 7 "const_int_operand")]            ;; model fail
412   ""
414   rs6000_expand_atomic_compare_and_swap (operands);
415   DONE;
418 (define_expand "atomic_exchange<mode>"
419   [(match_operand:AINT 0 "int_reg_operand")             ;; output
420    (match_operand:AINT 1 "memory_operand")              ;; memory
421    (match_operand:AINT 2 "int_reg_operand")             ;; input
422    (match_operand:SI 3 "const_int_operand")]            ;; model
423   ""
425   rs6000_expand_atomic_exchange (operands);
426   DONE;
429 (define_expand "atomic_<fetchop_name><mode>"
430   [(match_operand:AINT 0 "memory_operand")              ;; memory
431    (FETCHOP:AINT (match_dup 0)
432      (match_operand:AINT 1 "<fetchop_pred>"))           ;; operand
433    (match_operand:SI 2 "const_int_operand")]            ;; model
434   ""
436   rs6000_expand_atomic_op (<CODE>, operands[0], operands[1],
437                            NULL_RTX, NULL_RTX, operands[2]);
438   DONE;
441 (define_expand "atomic_nand<mode>"
442   [(match_operand:AINT 0 "memory_operand")              ;; memory
443    (match_operand:AINT 1 "int_reg_operand")             ;; operand
444    (match_operand:SI 2 "const_int_operand")]            ;; model
445   ""
447   rs6000_expand_atomic_op (NOT, operands[0], operands[1],
448                            NULL_RTX, NULL_RTX, operands[2]);
449   DONE;
452 (define_expand "atomic_fetch_<fetchop_name><mode>"
453   [(match_operand:AINT 0 "int_reg_operand")             ;; output
454    (match_operand:AINT 1 "memory_operand")              ;; memory
455    (FETCHOP:AINT (match_dup 1)
456      (match_operand:AINT 2 "<fetchop_pred>"))           ;; operand
457    (match_operand:SI 3 "const_int_operand")]            ;; model
458   ""
460   rs6000_expand_atomic_op (<CODE>, operands[1], operands[2],
461                            operands[0], NULL_RTX, operands[3]);
462   DONE;
465 (define_expand "atomic_fetch_nand<mode>"
466   [(match_operand:AINT 0 "int_reg_operand")             ;; output
467    (match_operand:AINT 1 "memory_operand")              ;; memory
468    (match_operand:AINT 2 "int_reg_operand")             ;; operand
469    (match_operand:SI 3 "const_int_operand")]            ;; model
470   ""
472   rs6000_expand_atomic_op (NOT, operands[1], operands[2],
473                            operands[0], NULL_RTX, operands[3]);
474   DONE;
477 (define_expand "atomic_<fetchop_name>_fetch<mode>"
478   [(match_operand:AINT 0 "int_reg_operand")             ;; output
479    (match_operand:AINT 1 "memory_operand")              ;; memory
480    (FETCHOP:AINT (match_dup 1)
481      (match_operand:AINT 2 "<fetchop_pred>"))           ;; operand
482    (match_operand:SI 3 "const_int_operand")]            ;; model
483   ""
485   rs6000_expand_atomic_op (<CODE>, operands[1], operands[2],
486                            NULL_RTX, operands[0], operands[3]);
487   DONE;
490 (define_expand "atomic_nand_fetch<mode>"
491   [(match_operand:AINT 0 "int_reg_operand")             ;; output
492    (match_operand:AINT 1 "memory_operand")              ;; memory
493    (match_operand:AINT 2 "int_reg_operand")             ;; operand
494    (match_operand:SI 3 "const_int_operand")]            ;; model
495   ""
497   rs6000_expand_atomic_op (NOT, operands[1], operands[2],
498                            NULL_RTX, operands[0], operands[3]);
499   DONE;