1;; GCC machine description for IA-64 synchronization instructions.
2;; Copyright (C) 2005-2020 Free Software Foundation, Inc.
3;;
4;; This file is part of GCC.
5;;
6;; GCC is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 3, or (at your option)
9;; any later version.
10;;
11;; GCC is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14;; GNU General Public License for more details.
15;;
16;; You should have received a copy of the GNU General Public License
17;; along with GCC; see the file COPYING3.  If not see
18;; <http://www.gnu.org/licenses/>.
19
20;; Conversion to C++11 memory model based on
21;; http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
22
23(define_mode_iterator IMODE [QI HI SI DI])
24(define_mode_iterator I124MODE [QI HI SI])
25(define_mode_iterator I48MODE [SI DI])
26(define_mode_attr modesuffix [(QI "1") (HI "2") (SI "4") (DI "8")])
27
28(define_code_iterator FETCHOP [plus minus ior xor and])
29(define_code_attr fetchop_name
30  [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")])
31
32(define_expand "mem_thread_fence"
33  [(match_operand:SI 0 "const_int_operand" "")]		;; model
34  ""
35{
36  if (is_mm_seq_cst (memmodel_from_int (INTVAL (operands[0]))))
37    emit_insn (gen_memory_barrier ());
38  DONE;
39})
40
41(define_expand "memory_barrier"
42  [(set (match_dup 0)
43	(unspec:BLK [(match_dup 0)] UNSPEC_MF))]
44  ""
45{
46  operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
47  MEM_VOLATILE_P (operands[0]) = 1;
48})
49
50(define_insn "*memory_barrier"
51  [(set (match_operand:BLK 0 "" "")
52	(unspec:BLK [(match_dup 0)] UNSPEC_MF))]
53  ""
54  "mf"
55  [(set_attr "itanium_class" "syst_m")])
56
57(define_expand "atomic_load<mode>"
58  [(match_operand:IMODE 0 "gr_register_operand" "")		;; output
59   (match_operand:IMODE 1 "memory_operand" "")			;; memory
60   (match_operand:SI 2 "const_int_operand" "")]			;; model
61  ""
62{
63  enum memmodel model = memmodel_from_int (INTVAL (operands[2]));
64
65  /* Unless the memory model is relaxed, we want to emit ld.acq, which
66     will happen automatically for volatile memories.  */
67  gcc_assert (is_mm_relaxed (model) || MEM_VOLATILE_P (operands[1]));
68  emit_move_insn (operands[0], operands[1]);
69  DONE;
70})
71
72(define_expand "atomic_store<mode>"
73  [(match_operand:IMODE 0 "memory_operand" "")			;; memory
74   (match_operand:IMODE 1 "gr_reg_or_0_operand" "")		;; input
75   (match_operand:SI 2 "const_int_operand" "")]			;; model
76  ""
77{
78  enum memmodel model = memmodel_from_int (INTVAL (operands[2]));
79
80  /* Unless the memory model is relaxed, we want to emit st.rel, which
81     will happen automatically for volatile memories.  */
82  gcc_assert (is_mm_relaxed (model) || MEM_VOLATILE_P (operands[0]));
83  emit_move_insn (operands[0], operands[1]);
84
85  /* Sequentially consistent stores need a subsequent MF.  See
86     http://www.decadent.org.uk/pipermail/cpp-threads/2008-December/001952.html
87     for a discussion of why a MF is needed here, but not for atomic_load.  */
88  if (is_mm_seq_cst (model))
89    emit_insn (gen_memory_barrier ());
90  DONE;
91})
92
93(define_expand "atomic_compare_and_swap<mode>"
94  [(match_operand:DI 0 "gr_register_operand" "")		;; bool out
95   (match_operand:IMODE 1 "gr_register_operand" "")		;; val out
96   (match_operand:IMODE 2 "not_postinc_memory_operand" "")	;; memory
97   (match_operand:IMODE 3 "gr_register_operand" "")		;; expected
98   (match_operand:IMODE 4 "gr_reg_or_0_operand" "")		;; desired
99   (match_operand:SI 5 "const_int_operand" "")			;; is_weak
100   (match_operand:SI 6 "const_int_operand" "")			;; succ model
101   (match_operand:SI 7 "const_int_operand" "")]			;; fail model
102  ""
103{
104  /* No need to distinquish __sync from __atomic, so get base value.  */
105  enum memmodel model = memmodel_base (INTVAL (operands[6]));
106  rtx ccv = gen_rtx_REG (DImode, AR_CCV_REGNUM);
107  rtx dval, eval;
108
109  eval = gen_reg_rtx (DImode);
110  convert_move (eval, operands[3], 1);
111  emit_move_insn (ccv, eval);
112
113  if (<MODE>mode == DImode)
114    dval = operands[1];
115  else
116    dval = gen_reg_rtx (DImode);
117
118  switch (model)
119    {
120    case MEMMODEL_RELAXED:
121    case MEMMODEL_ACQUIRE:
122    case MEMMODEL_CONSUME:
123      emit_insn (gen_cmpxchg_acq_<mode> (dval, operands[2], ccv, operands[4]));
124      break;
125    case MEMMODEL_RELEASE:
126      emit_insn (gen_cmpxchg_rel_<mode> (dval, operands[2], ccv, operands[4]));
127      break;
128    case MEMMODEL_ACQ_REL:
129    case MEMMODEL_SEQ_CST:
130      emit_insn (gen_cmpxchg_rel_<mode> (dval, operands[2], ccv, operands[4]));
131      emit_insn (gen_memory_barrier ());
132      break;
133    default:
134      gcc_unreachable ();
135    }
136
137  if (<MODE>mode != DImode)
138    emit_move_insn (operands[1], gen_lowpart (<MODE>mode, dval));
139
140  emit_insn (gen_cstoredi4 (operands[0], gen_rtx_EQ (DImode, dval, eval),
141			    dval, eval));
142  DONE;
143})
144
145(define_insn "cmpxchg_acq_<mode>"
146  [(set (match_operand:DI 0 "gr_register_operand" "=r")
147	(zero_extend:DI
148	  (match_operand:I124MODE 1 "not_postinc_memory_operand" "+S")))
149   (set (match_dup 1)
150        (unspec:I124MODE
151	  [(match_dup 1)
152	   (match_operand:DI 2 "ar_ccv_reg_operand" "")
153	   (match_operand:I124MODE 3 "gr_reg_or_0_operand" "rO")]
154	  UNSPEC_CMPXCHG_ACQ))]
155  ""
156  "cmpxchg<modesuffix>.acq %0 = %1, %r3, %2"
157  [(set_attr "itanium_class" "sem")])
158
159(define_insn "cmpxchg_rel_<mode>"
160  [(set (match_operand:DI 0 "gr_register_operand" "=r")
161	(zero_extend:DI
162	  (match_operand:I124MODE 1 "not_postinc_memory_operand" "+S")))
163   (set (match_dup 1)
164        (unspec:I124MODE
165	  [(match_dup 1)
166	   (match_operand:DI 2 "ar_ccv_reg_operand" "")
167	   (match_operand:I124MODE 3 "gr_reg_or_0_operand" "rO")]
168	  UNSPEC_CMPXCHG_REL))]
169  ""
170  "cmpxchg<modesuffix>.rel %0 = %1, %r3, %2"
171  [(set_attr "itanium_class" "sem")])
172
173(define_insn "cmpxchg_acq_di"
174  [(set (match_operand:DI 0 "gr_register_operand" "=r")
175	(match_operand:DI 1 "not_postinc_memory_operand" "+S"))
176   (set (match_dup 1)
177        (unspec:DI [(match_dup 1)
178		    (match_operand:DI 2 "ar_ccv_reg_operand" "")
179		    (match_operand:DI 3 "gr_reg_or_0_operand" "rO")]
180		   UNSPEC_CMPXCHG_ACQ))]
181  ""
182  "cmpxchg8.acq %0 = %1, %r3, %2"
183  [(set_attr "itanium_class" "sem")])
184
185(define_insn "cmpxchg_rel_di"
186  [(set (match_operand:DI 0 "gr_register_operand" "=r")
187	(match_operand:DI 1 "not_postinc_memory_operand" "+S"))
188   (set (match_dup 1)
189        (unspec:DI [(match_dup 1)
190		    (match_operand:DI 2 "ar_ccv_reg_operand" "")
191		    (match_operand:DI 3 "gr_reg_or_0_operand" "rO")]
192		   UNSPEC_CMPXCHG_REL))]
193  ""
194  "cmpxchg8.rel %0 = %1, %r3, %2"
195  [(set_attr "itanium_class" "sem")])
196
197(define_expand "atomic_exchange<mode>"
198  [(match_operand:IMODE 0 "gr_register_operand" "")		;; output
199   (match_operand:IMODE 1 "not_postinc_memory_operand" "")	;; memory
200   (match_operand:IMODE 2 "gr_reg_or_0_operand" "")		;; input
201   (match_operand:SI 3 "const_int_operand" "")]			;; succ model
202  ""
203{
204  /* No need to distinquish __sync from __atomic, so get base value.  */
205  enum memmodel model = memmodel_base (INTVAL (operands[3]));
206
207  switch (model)
208    {
209    case MEMMODEL_RELAXED:
210    case MEMMODEL_ACQUIRE:
211    case MEMMODEL_CONSUME:
212      break;
213    case MEMMODEL_RELEASE:
214    case MEMMODEL_ACQ_REL:
215    case MEMMODEL_SEQ_CST:
216      emit_insn (gen_memory_barrier ());
217      break;
218    default:
219      gcc_unreachable ();
220    }
221  emit_insn (gen_xchg_acq_<mode> (operands[0], operands[1], operands[2]));
222  DONE;
223})
224
225;; Note that XCHG is always memory model acquire.
226(define_insn "xchg_acq_<mode>"
227  [(set (match_operand:IMODE 0 "gr_register_operand" "=r")
228        (match_operand:IMODE 1 "not_postinc_memory_operand" "+S"))
229   (set (match_dup 1)
230        (match_operand:IMODE 2 "gr_reg_or_0_operand" "rO"))]
231  ""
232  "xchg<modesuffix> %0 = %1, %r2"
233  [(set_attr "itanium_class" "sem")])
234
235(define_expand "atomic_<fetchop_name><mode>"
236  [(set (match_operand:IMODE 0 "memory_operand" "")
237	(FETCHOP:IMODE (match_dup 0)
238	  (match_operand:IMODE 1 "nonmemory_operand" "")))
239   (use (match_operand:SI 2 "const_int_operand" ""))]
240  ""
241{
242  ia64_expand_atomic_op (<CODE>, operands[0], operands[1], NULL, NULL,
243			 (enum memmodel) INTVAL (operands[2]));
244  DONE;
245})
246
247(define_expand "atomic_nand<mode>"
248  [(set (match_operand:IMODE 0 "memory_operand" "")
249	(not:IMODE
250	  (and:IMODE (match_dup 0)
251		     (match_operand:IMODE 1 "nonmemory_operand" ""))))
252   (use (match_operand:SI 2 "const_int_operand" ""))]
253  ""
254{
255  ia64_expand_atomic_op (NOT, operands[0], operands[1], NULL, NULL,
256			 (enum memmodel) INTVAL (operands[2]));
257  DONE;
258})
259
260(define_expand "atomic_fetch_<fetchop_name><mode>"
261  [(set (match_operand:IMODE 0 "gr_register_operand" "")
262	(FETCHOP:IMODE
263	  (match_operand:IMODE 1 "memory_operand" "")
264	  (match_operand:IMODE 2 "nonmemory_operand" "")))
265   (use (match_operand:SI 3 "const_int_operand" ""))]
266  ""
267{
268  ia64_expand_atomic_op (<CODE>, operands[1], operands[2], operands[0], NULL,
269			 (enum memmodel) INTVAL (operands[3]));
270  DONE;
271})
272
273(define_expand "atomic_fetch_nand<mode>"
274  [(set (match_operand:IMODE 0 "gr_register_operand" "")
275	(not:IMODE
276	  (and:IMODE (match_operand:IMODE 1 "memory_operand" "")
277		     (match_operand:IMODE 2 "nonmemory_operand" ""))))
278   (use (match_operand:SI 3 "const_int_operand" ""))]
279  ""
280{
281  ia64_expand_atomic_op (NOT, operands[1], operands[2], operands[0], NULL,
282			 (enum memmodel) INTVAL (operands[3]));
283  DONE;
284})
285
286(define_expand "atomic_<fetchop_name>_fetch<mode>"
287  [(set (match_operand:IMODE 0 "gr_register_operand" "")
288	(FETCHOP:IMODE
289	  (match_operand:IMODE 1 "memory_operand" "")
290	  (match_operand:IMODE 2 "nonmemory_operand" "")))
291   (use (match_operand:SI 3 "const_int_operand" ""))]
292  ""
293{
294  ia64_expand_atomic_op (<CODE>, operands[1], operands[2], NULL, operands[0],
295			 (enum memmodel) INTVAL (operands[3]));
296  DONE;
297})
298
299(define_expand "atomic_nand_fetch<mode>"
300  [(set (match_operand:IMODE 0 "gr_register_operand" "")
301	(not:IMODE
302	  (and:IMODE (match_operand:IMODE 1 "memory_operand" "")
303		     (match_operand:IMODE 2 "nonmemory_operand" ""))))
304   (use (match_operand:SI 3 "const_int_operand" ""))]
305  ""
306{
307  ia64_expand_atomic_op (NOT, operands[1], operands[2], NULL, operands[0],
308			 (enum memmodel) INTVAL (operands[3]));
309  DONE;
310})
311
312(define_insn "fetchadd_acq_<mode>"
313  [(set (match_operand:I48MODE 0 "gr_register_operand" "=r")
314	(match_operand:I48MODE 1 "not_postinc_memory_operand" "+S"))
315   (set (match_dup 1)
316	(unspec:I48MODE [(match_dup 1)
317			 (match_operand:I48MODE 2 "fetchadd_operand" "n")]
318		        UNSPEC_FETCHADD_ACQ))]
319  ""
320  "fetchadd<modesuffix>.acq %0 = %1, %2"
321  [(set_attr "itanium_class" "sem")])
322
323(define_insn "fetchadd_rel_<mode>"
324  [(set (match_operand:I48MODE 0 "gr_register_operand" "=r")
325	(match_operand:I48MODE 1 "not_postinc_memory_operand" "+S"))
326   (set (match_dup 1)
327	(unspec:I48MODE [(match_dup 1)
328			 (match_operand:I48MODE 2 "fetchadd_operand" "n")]
329		        UNSPEC_FETCHADD_REL))]
330  ""
331  "fetchadd<modesuffix>.rel %0 = %1, %2"
332  [(set_attr "itanium_class" "sem")])
333