1 ;; GCC machine description for Alpha synchronization instructions.
3 ;; Free Software Foundation, Inc.
5 ;; This file is part of GCC.
7 ;; GCC is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation; either version 2, or (at your option)
12 ;; GCC is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GCC; see the file COPYING. If not, write to
19 ;; the Free Software Foundation, 59 Temple Place - Suite 330,
20 ;; Boston, MA 02111-1307, USA.
22 (define_mode_macro I48MODE [SI DI])
23 (define_mode_attr modesuffix [(SI "l") (DI "q")])
25 (define_code_macro FETCHOP [plus minus ior xor and])
26 (define_code_attr fetchop_name
27 [(plus "add") (minus "sub") (ior "ior") (xor "xor") (and "and")])
28 (define_code_attr fetchop_pred
29 [(plus "add_operand") (minus "reg_or_8bit_operand")
30 (ior "or_operand") (xor "or_operand") (and "and_operand")])
31 (define_code_attr fetchop_constr
32 [(plus "rKL") (minus "rI") (ior "rIN") (xor "rIN") (and "riNHM")])
35 (define_expand "memory_barrier"
36 [(set (mem:BLK (match_dup 0))
37 (unspec_volatile:BLK [(mem:BLK (match_dup 0))] UNSPECV_MB))]
40 operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (DImode));
41 MEM_VOLATILE_P (operands[0]) = 1;
44 (define_insn "*mb_internal"
45 [(set (match_operand:BLK 0 "" "")
46 (unspec_volatile:BLK [(match_operand:BLK 1 "" "")] UNSPECV_MB))]
49 [(set_attr "type" "mb")])
51 (define_insn "load_locked_<mode>"
52 [(set (match_operand:I48MODE 0 "register_operand" "=r")
53 (unspec_volatile:I48MODE
54 [(match_operand:I48MODE 1 "memory_operand" "m")]
57 "ld<modesuffix>_l %0,%1"
58 [(set_attr "type" "ld_l")])
60 (define_insn "store_conditional_<mode>"
61 [(set (match_operand:DI 0 "register_operand" "=r")
62 (unspec_volatile:DI [(const_int 0)] UNSPECV_SC))
63 (set (match_operand:I48MODE 1 "memory_operand" "=m")
64 (match_operand:I48MODE 2 "reg_or_0_operand" "0"))]
66 "st<modesuffix>_c %0,%1"
67 [(set_attr "type" "st_c")])
69 ;; The Alpha Architecture Handbook says that it is UNPREDICTABLE whether
70 ;; the lock is cleared by a TAKEN branch. If we were to honor that, it
71 ;; would mean that we could not expand a ll/sc sequence until after the
72 ;; final basic-block reordering pass. Fortunately, it appears that no
73 ;; Alpha implementation ever built actually clears the lock on branches,
76 (define_insn_and_split "sync_<fetchop_name><mode>"
77 [(set (match_operand:I48MODE 0 "memory_operand" "+m")
78 (unspec_volatile:I48MODE
79 [(FETCHOP:I48MODE (match_dup 0)
80 (match_operand:I48MODE 1 "<fetchop_pred>" "<fetchop_constr>"))]
82 (clobber (match_scratch:I48MODE 2 "=&r"))]
88 alpha_split_atomic_op (<CODE>, operands[0], operands[1],
89 NULL, NULL, operands[2]);
92 [(set_attr "type" "multi")])
94 (define_insn_and_split "sync_nand<mode>"
95 [(set (match_operand:I48MODE 0 "memory_operand" "+m")
96 (unspec_volatile:I48MODE
97 [(and:I48MODE (not:I48MODE (match_dup 0))
98 (match_operand:I48MODE 1 "register_operand" "r"))]
100 (clobber (match_scratch:I48MODE 2 "=&r"))]
106 alpha_split_atomic_op (NOT, operands[0], operands[1],
107 NULL, NULL, operands[2]);
110 [(set_attr "type" "multi")])
112 (define_insn_and_split "sync_old_<fetchop_name><mode>"
113 [(set (match_operand:I48MODE 0 "register_operand" "=&r")
114 (match_operand:I48MODE 1 "memory_operand" "+m"))
116 (unspec_volatile:I48MODE
117 [(FETCHOP:I48MODE (match_dup 1)
118 (match_operand:I48MODE 2 "<fetchop_pred>" "<fetchop_constr>"))]
120 (clobber (match_scratch:I48MODE 3 "=&r"))]
126 alpha_split_atomic_op (<CODE>, operands[1], operands[2],
127 operands[0], NULL, operands[3]);
130 [(set_attr "type" "multi")])
132 (define_insn_and_split "sync_old_nand<mode>"
133 [(set (match_operand:I48MODE 0 "register_operand" "=&r")
134 (match_operand:I48MODE 1 "memory_operand" "+m"))
136 (unspec_volatile:I48MODE
137 [(and:I48MODE (not:I48MODE (match_dup 1))
138 (match_operand:I48MODE 2 "register_operand" "r"))]
140 (clobber (match_scratch:I48MODE 3 "=&r"))]
146 alpha_split_atomic_op (NOT, operands[1], operands[2],
147 operands[0], NULL, operands[3]);
150 [(set_attr "type" "multi")])
152 (define_insn_and_split "sync_new_<fetchop_name><mode>"
153 [(set (match_operand:I48MODE 0 "register_operand" "=&r")
155 (match_operand:I48MODE 1 "memory_operand" "+m")
156 (match_operand:I48MODE 2 "<fetchop_pred>" "<fetchop_constr>")))
158 (unspec_volatile:I48MODE
159 [(FETCHOP:I48MODE (match_dup 1) (match_dup 2))]
161 (clobber (match_scratch:I48MODE 3 "=&r"))]
167 alpha_split_atomic_op (<CODE>, operands[1], operands[2],
168 NULL, operands[0], operands[3]);
171 [(set_attr "type" "multi")])
173 (define_insn_and_split "sync_new_nand<mode>"
174 [(set (match_operand:I48MODE 0 "register_operand" "=&r")
176 (not:I48MODE (match_operand:I48MODE 1 "memory_operand" "+m"))
177 (match_operand:I48MODE 2 "reg_or_8bit_operand" "rI")))
179 (unspec_volatile:I48MODE
180 [(and:I48MODE (not:I48MODE (match_dup 1)) (match_dup 2))]
182 (clobber (match_scratch:I48MODE 3 "=&r"))]
188 alpha_split_atomic_op (NOT, operands[1], operands[2],
189 NULL, operands[0], operands[3]);
192 [(set_attr "type" "multi")])
194 (define_expand "sync_compare_and_swap<mode>"
196 [(set (match_operand:I48MODE 0 "register_operand" "")
197 (match_operand:I48MODE 1 "memory_operand" ""))
199 (unspec_volatile:I48MODE
200 [(match_operand:I48MODE 2 "reg_or_8bit_operand" "")
201 (match_operand:I48MODE 3 "add_operand" "rKL")]
203 (clobber (match_scratch:I48MODE 4 "=&r"))])]
206 if (<MODE>mode == SImode)
207 operands[2] = convert_modes (DImode, SImode, operands[2], 0);
210 (define_insn_and_split "*sync_compare_and_swap<mode>"
211 [(set (match_operand:I48MODE 0 "register_operand" "=&r")
212 (match_operand:I48MODE 1 "memory_operand" "+m"))
214 (unspec_volatile:I48MODE
215 [(match_operand:DI 2 "reg_or_8bit_operand" "rI")
216 (match_operand:I48MODE 3 "add_operand" "rKL")]
218 (clobber (match_scratch:I48MODE 4 "=&r"))]
224 rtx retval, mem, oldval, newval, scratch;
225 rtx cond, label1, label2, x;
226 rtx very_unlikely = GEN_INT (REG_BR_PROB_BASE / 100 - 1);
228 retval = operands[0];
230 oldval = operands[2];
231 newval = operands[3];
232 scratch = operands[4];
233 cond = gen_lowpart (DImode, scratch);
235 emit_insn (gen_memory_barrier ());
237 label1 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
238 label2 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
239 emit_label (XEXP (label1, 0));
241 emit_insn (gen_load_locked_<mode> (retval, mem));
243 x = gen_lowpart (DImode, retval);
244 if (oldval == const0_rtx)
245 x = gen_rtx_NE (DImode, x, const0_rtx);
248 x = gen_rtx_EQ (DImode, x, oldval);
249 emit_insn (gen_rtx_SET (VOIDmode, cond, x));
250 x = gen_rtx_EQ (DImode, cond, const0_rtx);
252 x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label2, pc_rtx);
253 x = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, x));
254 REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_BR_PROB, very_unlikely, NULL_RTX);
256 emit_move_insn (scratch, newval);
258 emit_insn (gen_store_conditional_<mode> (cond, mem, scratch));
260 x = gen_rtx_EQ (DImode, cond, const0_rtx);
261 x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label1, pc_rtx);
262 x = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, x));
263 REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_BR_PROB, very_unlikely, NULL_RTX);
265 emit_insn (gen_memory_barrier ());
266 emit_label (XEXP (label2, 0));
269 [(set_attr "type" "multi")])
271 (define_insn_and_split "sync_lock_test_and_set<mode>"
272 [(set (match_operand:I48MODE 0 "register_operand" "=&r")
273 (match_operand:I48MODE 1 "memory_operand" "+m"))
275 (unspec_volatile:I48MODE
276 [(match_operand:I48MODE 2 "add_operand" "rKL")]
278 (clobber (match_scratch:I48MODE 3 "=&r"))]
284 rtx retval, mem, val, scratch;
286 rtx very_unlikely = GEN_INT (REG_BR_PROB_BASE / 100 - 1);
288 retval = operands[0];
291 scratch = operands[3];
292 cond = gen_lowpart (DImode, scratch);
294 emit_insn (gen_memory_barrier ());
296 label1 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
297 emit_label (XEXP (label1, 0));
299 emit_insn (gen_load_locked_<mode> (retval, mem));
301 emit_move_insn (scratch, val);
303 emit_insn (gen_store_conditional_<mode> (cond, mem, scratch));
305 x = gen_rtx_EQ (DImode, cond, const0_rtx);
306 x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label1, pc_rtx);
307 x = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, x));
308 REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_BR_PROB, very_unlikely, NULL_RTX);
312 [(set_attr "type" "multi")])