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