]> 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.
a945c346 2;; Copyright (C) 2005-2024 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 40(define_expand "mem_thread_fence"
ad18eed2 41 [(match_operand:SI 0 "const_int_operand")] ;; model
2747a046
RH
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 if (TARGET_NO_LWSYNC)
95 return "sync";
2747a046 96 else
2660fecc 97 return "lwsync";
2747a046
RH
98}
99 [(set_attr "type" "sync")])
9fc75b97 100
2747a046
RH
101(define_insn "isync"
102 [(unspec_volatile:BLK [(const_int 0)] UNSPECV_ISYNC)]
103 ""
6b39bc38 104 "isync"
2747a046 105 [(set_attr "type" "isync")])
9fc75b97 106
bf245bf4
PH
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
2747a046
RH
114;; The control dependency used for load dependency described
115;; in B.2.3 of the Power ISA 2.06B.
1ba24090 116(define_insn "loadsync_<mode>"
bf245bf4 117 [(unspec_volatile:BLK [(match_operand:AINT 0 "register_operand" "r")]
2747a046
RH
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
3bcdb5de 125;; If TARGET_PREFIXED, always use plq rather than lq.
bf245bf4
PH
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"
3bcdb5de 133 [(set_attr "type" "load")
9a5a1e27 134 (set_attr "size" "128")
3bcdb5de
AS
135 (set (attr "prefixed") (if_then_else (match_test "TARGET_PREFIXED")
136 (const_string "yes")
137 (const_string "no")))])
138
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.
2747a046 146(define_expand "atomic_load<mode>"
ad18eed2
SB
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
2747a046 150 ""
9fc75b97 151{
bf245bf4
PH
152 if (<MODE>mode == TImode && !TARGET_SYNC_TI)
153 FAIL;
154
39e150e8 155 enum memmodel model = memmodel_base (INTVAL (operands[2]));
9fc75b97 156
46b35980 157 if (is_mm_seq_cst (model))
2747a046 158 emit_insn (gen_hwsync ());
f565b0a1 159
bf245bf4
PH
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);
167
ba6bf284 168 if (!quad_address_p (XEXP (op1, 0), TImode, false))
bf245bf4
PH
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 }
174
175 emit_insn (gen_load_quadpti (pti_reg, op1));
176
3bcdb5de 177 if (WORDS_BIG_ENDIAN || TARGET_PREFIXED)
bf245bf4
PH
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 }
2747a046
RH
185
186 switch (model)
9f0076e5 187 {
2747a046
RH
188 case MEMMODEL_RELAXED:
189 break;
190 case MEMMODEL_CONSUME:
191 case MEMMODEL_ACQUIRE:
192 case MEMMODEL_SEQ_CST:
4b02c962 193 emit_insn (gen_loadsync_<mode> (operands[0]));
2747a046
RH
194 break;
195 default:
196 gcc_unreachable ();
9f0076e5 197 }
f565b0a1 198 DONE;
9f0076e5 199})
f565b0a1 200
3bcdb5de 201;; If TARGET_PREFIXED, always use pstq rather than stq.
bf245bf4
PH
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"
3bcdb5de 208 [(set_attr "type" "store")
9a5a1e27 209 (set_attr "size" "128")
3bcdb5de
AS
210 (set (attr "prefixed") (if_then_else (match_test "TARGET_PREFIXED")
211 (const_string "yes")
212 (const_string "no")))])
bf245bf4 213
3bcdb5de
AS
214;; Pattern store_quadpti will always use pstq if TARGET_PREFIXED,
215;; so the doubleword swap is never needed in that case.
2747a046 216(define_expand "atomic_store<mode>"
ad18eed2
SB
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
2747a046 220 ""
f565b0a1 221{
bf245bf4
PH
222 if (<MODE>mode == TImode && !TARGET_SYNC_TI)
223 FAIL;
224
39e150e8 225 enum memmodel model = memmodel_base (INTVAL (operands[2]));
2747a046
RH
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 }
bf245bf4
PH
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);
246
ba6bf284 247 if (!quad_address_p (XEXP (op0, 0), TImode, false))
bf245bf4
PH
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 }
253
3bcdb5de 254 if (WORDS_BIG_ENDIAN || TARGET_PREFIXED)
bf245bf4
PH
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 }
261
262 emit_insn (gen_store_quadpti (gen_lowpart (PTImode, op0), pti_reg));
263 }
264
f565b0a1 265 DONE;
9f0076e5 266})
f565b0a1 267
4b02c962
MM
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")])
277
2747a046 278(define_insn "load_locked<mode>"
4b02c962 279 [(set (match_operand:ATOMIC 0 "int_reg_operand" "=r")
2747a046
RH
280 (unspec_volatile:ATOMIC
281 [(match_operand:ATOMIC 1 "memory_operand" "Z")] UNSPECV_LL))]
a441dedb 282 ""
2747a046
RH
283 "<larx> %0,%y1"
284 [(set_attr "type" "load_l")])
f565b0a1 285
4b02c962
MM
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")])
293
b846c948
MM
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.
298
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.
302
4b02c962 303(define_expand "load_lockedti"
ad18eed2
SB
304 [(use (match_operand:TI 0 "quad_int_reg_operand"))
305 (use (match_operand:TI 1 "memory_operand"))]
4b02c962
MM
306 "TARGET_SYNC_TI"
307{
b846c948
MM
308 rtx op0 = operands[0];
309 rtx op1 = operands[1];
4b02c962 310 rtx pti = gen_reg_rtx (PTImode);
b846c948
MM
311
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 }
318
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 }
4b02c962
MM
327 DONE;
328})
329
330(define_insn "load_lockedpti"
331 [(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r")
332 (unspec_volatile:PTI
b846c948 333 [(match_operand:TI 1 "indexed_or_indirect_operand" "Z")] UNSPECV_LL))]
4b02c962
MM
334 "TARGET_SYNC_TI
335 && !reg_mentioned_p (operands[0], operands[1])
336 && quad_int_reg_operand (operands[0], PTImode)"
337 "lqarx %0,%y1"
9a5a1e27
PH
338 [(set_attr "type" "load_l")
339 (set_attr "size" "128")])
4b02c962 340
2747a046
RH
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")
4b02c962 345 (match_operand:ATOMIC 2 "int_reg_operand" "r"))]
a441dedb 346 ""
2747a046
RH
347 "<stcx> %2,%y1"
348 [(set_attr "type" "store_c")])
f565b0a1 349
b846c948
MM
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.
353
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.
357
4b02c962 358(define_expand "store_conditionalti"
ad18eed2
SB
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"))]
4b02c962
MM
362 "TARGET_SYNC_TI"
363{
364 rtx op0 = operands[0];
365 rtx op1 = operands[1];
366 rtx op2 = operands[2];
b846c948
MM
367 rtx addr = XEXP (op1, 0);
368 rtx pti_mem;
369 rtx pti_reg;
370
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 }
377
378 pti_mem = change_address (op1, PTImode, addr);
379 pti_reg = gen_reg_rtx (PTImode);
380
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 }
388
389 emit_insn (gen_store_conditionalpti (op0, pti_mem, pti_reg));
4b02c962
MM
390 DONE;
391})
392
393(define_insn "store_conditionalpti"
394 [(set (match_operand:CC 0 "cc_reg_operand" "=x")
395 (unspec_volatile:CC [(const_int 0)] UNSPECV_SC))
b846c948 396 (set (match_operand:PTI 1 "indexed_or_indirect_operand" "=Z")
4b02c962
MM
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"
9a5a1e27
PH
400 [(set_attr "type" "store_c")
401 (set_attr "size" "128")])
4b02c962 402
2747a046 403(define_expand "atomic_compare_and_swap<mode>"
ad18eed2
SB
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
a441dedb 412 ""
f565b0a1 413{
2747a046 414 rs6000_expand_atomic_compare_and_swap (operands);
f565b0a1 415 DONE;
9f0076e5 416})
f565b0a1 417
2747a046 418(define_expand "atomic_exchange<mode>"
ad18eed2
SB
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
a441dedb 423 ""
f565b0a1 424{
2747a046 425 rs6000_expand_atomic_exchange (operands);
f565b0a1 426 DONE;
9f0076e5 427})
f565b0a1 428
2747a046 429(define_expand "atomic_<fetchop_name><mode>"
ad18eed2 430 [(match_operand:AINT 0 "memory_operand") ;; memory
4b02c962 431 (FETCHOP:AINT (match_dup 0)
ad18eed2
SB
432 (match_operand:AINT 1 "<fetchop_pred>")) ;; operand
433 (match_operand:SI 2 "const_int_operand")] ;; model
a441dedb 434 ""
f565b0a1 435{
2747a046
RH
436 rs6000_expand_atomic_op (<CODE>, operands[0], operands[1],
437 NULL_RTX, NULL_RTX, operands[2]);
f565b0a1 438 DONE;
9f0076e5 439})
f565b0a1 440
2747a046 441(define_expand "atomic_nand<mode>"
ad18eed2
SB
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
a441dedb 445 ""
f565b0a1 446{
2747a046
RH
447 rs6000_expand_atomic_op (NOT, operands[0], operands[1],
448 NULL_RTX, NULL_RTX, operands[2]);
f565b0a1 449 DONE;
9f0076e5 450})
f565b0a1 451
2747a046 452(define_expand "atomic_fetch_<fetchop_name><mode>"
ad18eed2
SB
453 [(match_operand:AINT 0 "int_reg_operand") ;; output
454 (match_operand:AINT 1 "memory_operand") ;; memory
4b02c962 455 (FETCHOP:AINT (match_dup 1)
ad18eed2
SB
456 (match_operand:AINT 2 "<fetchop_pred>")) ;; operand
457 (match_operand:SI 3 "const_int_operand")] ;; model
a441dedb 458 ""
2747a046
RH
459{
460 rs6000_expand_atomic_op (<CODE>, operands[1], operands[2],
461 operands[0], NULL_RTX, operands[3]);
f565b0a1 462 DONE;
9f0076e5 463})
f565b0a1 464
2747a046 465(define_expand "atomic_fetch_nand<mode>"
ad18eed2
SB
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
a441dedb 470 ""
f565b0a1 471{
2747a046
RH
472 rs6000_expand_atomic_op (NOT, operands[1], operands[2],
473 operands[0], NULL_RTX, operands[3]);
474 DONE;
475})
f565b0a1 476
2747a046 477(define_expand "atomic_<fetchop_name>_fetch<mode>"
ad18eed2
SB
478 [(match_operand:AINT 0 "int_reg_operand") ;; output
479 (match_operand:AINT 1 "memory_operand") ;; memory
4b02c962 480 (FETCHOP:AINT (match_dup 1)
ad18eed2
SB
481 (match_operand:AINT 2 "<fetchop_pred>")) ;; operand
482 (match_operand:SI 3 "const_int_operand")] ;; model
a441dedb 483 ""
f565b0a1 484{
2747a046
RH
485 rs6000_expand_atomic_op (<CODE>, operands[1], operands[2],
486 NULL_RTX, operands[0], operands[3]);
f565b0a1 487 DONE;
9f0076e5
DE
488})
489
2747a046 490(define_expand "atomic_nand_fetch<mode>"
ad18eed2
SB
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
a441dedb 495 ""
f565b0a1 496{
2747a046
RH
497 rs6000_expand_atomic_op (NOT, operands[1], operands[2],
498 NULL_RTX, operands[0], operands[3]);
f565b0a1 499 DONE;
2747a046 500})