1;; GCC machine description for ARC atomic instructions.
2;; Copyright (C) 2015-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(define_mode_iterator QHSI [QI HI SI])
21(define_code_iterator atomicop [plus minus ior xor and])
22(define_code_attr atomic_optab
23  [(ior "or") (xor "xor") (and "and") (plus "add") (minus "sub")])
24
25(define_expand "memory_barrier"
26  [(set (match_dup 0)
27	(unspec:BLK [(match_dup 0)] UNSPEC_ARC_MEMBAR))]
28  ""
29{
30  operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
31  MEM_VOLATILE_P (operands[0]) = 1;
32})
33
34;; A compiler-only memory barrier for ARC700.  Generic code, when
35;; checking for the existence of various named patterns, uses
36;; asm("":::"memory") when we don't need an actual instruction.  For
37;; ARCHS, we use a hardware data memory barrier that waits for
38;; completion of current data memory operations before initiating
39;; similar data memory operations.
40(define_insn "*memory_barrier"
41  [(set (match_operand:BLK 0 "" "")
42	(unspec:BLK [(match_dup 0)] UNSPEC_ARC_MEMBAR))]
43  ""
44  {
45   if (TARGET_HS)
46      {
47       return "dmb\\t3";
48      }
49    else
50      {
51       return "";
52      }
53  }
54  [(set_attr "type" "multi")
55   (set_attr "length" "4")])
56
57(define_expand "atomic_compare_and_swap<mode>"
58  [(match_operand:SI 0 "register_operand" "")	;; bool out
59   (match_operand:QHSI 1 "register_operand" "")	;; val out
60   (match_operand:QHSI 2 "mem_noofs_operand" "");; memory
61   (match_operand:QHSI 3 "register_operand" "")	;; expected
62   (match_operand:QHSI 4 "register_operand" "")	;; desired
63   (match_operand:SI 5 "const_int_operand")	;; is_weak
64   (match_operand:SI 6 "const_int_operand")	;; mod_s
65   (match_operand:SI 7 "const_int_operand")]	;; mod_f
66  "TARGET_ATOMIC"
67{
68  arc_expand_compare_and_swap (operands);
69  DONE;
70})
71
72(define_insn_and_split "atomic_compare_and_swapsi_1"
73  [(set (reg:CC_Z CC_REG)					;; bool out
74	(unspec_volatile:CC_Z [(const_int 0)] VUNSPEC_ARC_CAS))
75   (set (match_operand:SI 0 "register_operand"      "=&r")	;; val out
76	(match_operand:SI 1 "mem_noofs_operand"      "+ATO"))	;; memory
77   (set (match_dup 1)
78	(unspec_volatile:SI
79	  [(match_operand:SI 2 "register_operand"     "r") ;; expect
80	   (match_operand:SI 3 "register_operand"     "r") ;; desired
81	   (match_operand:SI 4 "const_int_operand")	   ;; is_weak
82	   (match_operand:SI 5 "const_int_operand")	   ;; mod_s
83	   (match_operand:SI 6 "const_int_operand")]	   ;; mod_f
84	  VUNSPEC_ARC_CAS))]
85  "TARGET_ATOMIC"
86  "#"
87  "&& reload_completed"
88  [(const_int 0)]
89  {
90    arc_split_compare_and_swap (operands);
91    DONE;
92  })
93
94(define_insn "arc_load_exclusivesi"
95  [(set (match_operand:SI 0 "register_operand" "=r")
96	(unspec_volatile:SI
97	  [(match_operand:SI 1 "mem_noofs_operand" "ATO")]
98	  VUNSPEC_ARC_LL))]
99  "TARGET_ATOMIC"
100  "llock %0,%1"
101  [(set_attr "type" "load")
102   (set_attr "iscompact" "false")
103   (set_attr "predicable" "no")
104   (set_attr "length" "*")])
105
106(define_insn "arc_store_exclusivesi"
107  [(set (match_operand:SI 0 "mem_noofs_operand"     "=ATO")
108	(unspec_volatile:SI[(match_operand:SI 1 "register_operand" "r")]
109			   VUNSPEC_ARC_SC))
110   (clobber (reg:CC_Z CC_REG))]
111  "TARGET_ATOMIC"
112  "scond %1,%0"
113  [(set_attr "type" "store")
114   (set_attr "iscompact" "false")
115   (set_attr "predicable" "no")
116   (set_attr "length" "*")])
117
118(define_expand "atomic_exchangesi"
119  [(match_operand:SI 0 "register_operand" "")
120   (match_operand:SI 1 "mem_noofs_operand" "")
121   (match_operand:SI 2 "register_operand" "")
122   (match_operand:SI 3 "const_int_operand" "")]
123  "TARGET_ARC700 || TARGET_V2"
124{
125  enum memmodel model = (enum memmodel) INTVAL (operands[3]);
126
127  if (model == MEMMODEL_SEQ_CST)
128    emit_insn (gen_sync (const1_rtx));
129  emit_insn (gen_exchangesi (operands[0], operands[1], operands[2]));
130  DONE;
131})
132
133(define_insn "exchangesi"
134  [(set (match_operand:SI 0 "register_operand" "=r")
135	(unspec_volatile:SI [(match_operand:SI 1 "mem_noofs_operand" "+ATO")]
136			    VUNSPEC_ARC_EX))
137   (set (match_dup 1)
138	(match_operand:SI 2 "register_operand" "0"))]
139  ""
140  "ex %0,%1"
141  [(set_attr "type" "load")
142   (set_attr "iscompact" "false")
143   (set_attr "predicable" "no")
144   (set_attr "length" "*")])
145
146(define_expand "atomic_<atomic_optab>si"
147  [(match_operand:SI 0 "mem_noofs_operand" "")  ;; memory
148   (atomicop:SI (match_dup 0)
149		(match_operand:SI 1 "register_operand" "")) ;; operand
150   (match_operand:SI 2 "const_int_operand" "")] ;; model
151  "TARGET_ATOMIC"
152{
153  arc_expand_atomic_op (<CODE>, operands[0], operands[1],
154				NULL_RTX, NULL_RTX, operands[2]);
155  DONE;
156})
157
158(define_expand "atomic_nandsi"
159  [(match_operand:SI 0 "mem_noofs_operand" "")	;; memory
160   (match_operand:SI 1 "register_operand" "")	;; operand
161   (match_operand:SI 2 "const_int_operand" "")]	;; model
162  "TARGET_ATOMIC"
163{
164 arc_expand_atomic_op (NOT, operands[0], operands[1],
165			    NULL_RTX, NULL_RTX, operands[2]);
166 DONE;
167})
168
169(define_expand "atomic_fetch_<atomic_optab>si"
170  [(match_operand:SI 0 "register_operand" "")	;; output
171   (match_operand:SI 1 "mem_noofs_operand" "")	;; memory
172   (atomicop:SI (match_dup 1)
173		(match_operand:SI 2 "register_operand" "")) ;; operand
174   (match_operand:SI 3 "const_int_operand" "")]	;; model
175  "TARGET_ATOMIC"
176{
177  arc_expand_atomic_op (<CODE>, operands[1], operands[2],
178				operands[0], NULL_RTX, operands[3]);
179  DONE;
180})
181
182(define_expand "atomic_fetch_nandsi"
183  [(match_operand:SI 0 "register_operand" "")	;; output
184   (match_operand:SI 1 "mem_noofs_operand" "")	;; memory
185   (match_operand:SI 2 "register_operand" "")	;; operand
186   (match_operand:SI 3 "const_int_operand" "")]	;; model
187  "TARGET_ATOMIC"
188{
189  arc_expand_atomic_op (NOT, operands[1], operands[2],
190			     operands[0], NULL_RTX, operands[3]);
191  DONE;
192})
193
194(define_expand "atomic_<atomic_optab>_fetchsi"
195  [(match_operand:SI 0 "register_operand" "")	;; output
196   (match_operand:SI 1 "mem_noofs_operand" "")	;; memory
197   (atomicop:SI (match_dup 1)
198		(match_operand:SI 2 "register_operand" "")) ;; operand
199   (match_operand:SI 3 "const_int_operand" "")]	;; model
200  "TARGET_ATOMIC"
201{
202  arc_expand_atomic_op (<CODE>, operands[1], operands[2],
203				NULL_RTX, operands[0], operands[3]);
204  DONE;
205})
206
207(define_expand "atomic_nand_fetchsi"
208  [(match_operand:SI 0 "register_operand" "")	;; output
209   (match_operand:SI 1 "mem_noofs_operand" "")	;; memory
210   (match_operand:SI 2 "register_operand" "")	;; operand
211   (match_operand:SI 3 "const_int_operand" "")]	;; model
212  "TARGET_ATOMIC"
213{
214  arc_expand_atomic_op (NOT, operands[1], operands[2],
215			     NULL_RTX, operands[0], operands[3]);
216  DONE;
217})
218
219