1;; Predicate definitions for Renesas RX.
2;; Copyright (C) 2008-2021 Free Software Foundation, Inc.
3;; Contributed by Red Hat.
4;;
5;; This file is part of GCC.
6;;
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 3, or (at your option)
10;; any later version.
11;;
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.
16;;
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/>.
20
21
22
23;; Check that the operand is suitable for a call insn.
24;; Only registers and symbol refs are allowed.
25
26(define_predicate "rx_call_operand"
27  (ior (match_code "reg")
28       (and (match_test "!TARGET_JSR")
29	    (match_code "symbol_ref")))
30)
31
32;; For sibcall operations we can only use a symbolic address.
33
34(define_predicate "rx_symbolic_call_operand"
35  (match_code "symbol_ref")
36)
37
38;; Check that the operand is suitable for a shift insn
39;; Only small integers or a value in a register are permitted.
40
41(define_predicate "rx_shift_operand"
42  (ior (match_operand 0 "register_operand")
43       (and (match_code "const_int")
44	    (match_test "IN_RANGE (INTVAL (op), 0, 31)")))
45)
46
47(define_predicate "rx_constshift_operand"
48  (and (match_code "const_int")
49       (match_test "IN_RANGE (INTVAL (op), 0, 31)"))
50)
51
52(define_predicate "rx_restricted_mem_operand"
53  (and (match_code "mem")
54       (match_test "rx_is_restricted_memory_address (XEXP (op, 0), mode)"))
55)
56
57;; Check that the operand is suitable as the source operand
58;; for a logic or arithmeitc instruction.  Registers, integers
59;; and a restricted subset of memory addresses are allowed.
60
61(define_predicate "rx_source_operand"
62  (ior (match_operand 0 "register_operand")
63       (match_operand 0 "immediate_operand")
64       (match_operand 0 "rx_restricted_mem_operand"))
65)
66
67;; Check that the operand is suitable as the source operand
68;; for a comparison instruction.  This is the same as
69;; rx_source_operand except that SUBREGs are allowed but
70;; CONST_INTs are not.
71
72(define_predicate "rx_compare_operand"
73  (ior (match_operand 0 "register_operand")
74       (match_operand 0 "rx_restricted_mem_operand"))
75)
76
77;; Check that the operand is suitable as the source operand
78;; for a min/max instruction.  This is the same as
79;; rx_source_operand except that CONST_INTs are allowed but
80;; REGs and SUBREGs are not.
81
82(define_predicate "rx_minmaxex_operand"
83  (ior (match_operand 0 "immediate_operand")
84       (match_operand 0 "rx_restricted_mem_operand"))
85)
86
87;; Return true if OP is a store multiple operation.  This looks like:
88;;
89;;   [(set (SP) (MINUS (SP) (INT)))
90;;    (set (MEM (SP)) (REG))
91;;    (set (MEM (MINUS (SP) (INT))) (REG)) {optionally repeated}
92;;   ]
93
94(define_special_predicate "rx_store_multiple_vector"
95  (match_code "parallel")
96{
97  int count = XVECLEN (op, 0);
98  unsigned int src_regno;
99  rtx element;
100  int i;
101
102  /* Perform a quick check so we don't blow up below.  */
103  if (count <= 2)
104    return false;
105
106  /* Check that the first element of the vector is the stack adjust.  */
107  element = XVECEXP (op, 0, 0);
108  if (   ! SET_P (element)
109      || ! REG_P (SET_DEST (element))
110      ||   REGNO (SET_DEST (element)) != SP_REG
111      ||   GET_CODE (SET_SRC (element)) != MINUS
112      || ! REG_P (XEXP (SET_SRC (element), 0))
113      ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG
114      || ! CONST_INT_P (XEXP (SET_SRC (element), 1)))
115    return false;
116
117  /* Check that the next element is the first push.  */
118  element = XVECEXP (op, 0, 1);
119  if (   ! SET_P (element)
120      || ! REG_P (SET_SRC (element))
121      || GET_MODE (SET_SRC (element)) != SImode
122      || ! MEM_P (SET_DEST (element))
123      || GET_MODE (SET_DEST (element)) != SImode
124      || GET_CODE (XEXP (SET_DEST (element), 0)) != MINUS
125      || ! REG_P (XEXP (XEXP (SET_DEST (element), 0), 0))
126      ||   REGNO (XEXP (XEXP (SET_DEST (element), 0), 0)) != SP_REG
127      || ! CONST_INT_P (XEXP (XEXP (SET_DEST (element), 0), 1))
128      || INTVAL (XEXP (XEXP (SET_DEST (element), 0), 1))
129        != GET_MODE_SIZE (SImode))
130    return false;
131
132  src_regno = REGNO (SET_SRC (element));
133
134  /* Check that the remaining elements use SP-<disp>
135     addressing and decreasing register numbers.  */
136  for (i = 2; i < count; i++)
137    {
138      element = XVECEXP (op, 0, i);
139
140      if (   ! SET_P (element)
141	  || ! REG_P (SET_SRC (element))
142	  || GET_MODE (SET_SRC (element)) != SImode
143	  || REGNO (SET_SRC (element)) != src_regno - (i - 1)
144	  || ! MEM_P (SET_DEST (element))
145	  || GET_MODE (SET_DEST (element)) != SImode
146	  || GET_CODE (XEXP (SET_DEST (element), 0)) != MINUS
147          || ! REG_P (XEXP (XEXP (SET_DEST (element), 0), 0))
148          ||   REGNO (XEXP (XEXP (SET_DEST (element), 0), 0)) != SP_REG
149	  || ! CONST_INT_P (XEXP (XEXP (SET_DEST (element), 0), 1))
150	  || INTVAL (XEXP (XEXP (SET_DEST (element), 0), 1))
151	     != i * GET_MODE_SIZE (SImode))
152	return false;
153    }
154  return true;
155})
156
157;; Return true if OP is a load multiple operation.
158;; This looks like:
159;;  [(set (SP) (PLUS (SP) (INT)))
160;;   (set (REG) (MEM (SP)))
161;;   (set (REG) (MEM (PLUS (SP) (INT)))) {optionally repeated}
162;;  ]
163
164(define_special_predicate "rx_load_multiple_vector"
165  (match_code "parallel")
166{
167  int count = XVECLEN (op, 0);
168  unsigned int dest_regno;
169  rtx element;
170  int i;
171
172  /* Perform a quick check so we don't blow up below.  */
173  if (count <= 2)
174    return false;
175
176  /* Check that the first element of the vector is the stack adjust.  */
177  element = XVECEXP (op, 0, 0);
178  if (   ! SET_P (element)
179      || ! REG_P (SET_DEST (element))
180      ||   REGNO (SET_DEST (element)) != SP_REG
181      ||   GET_CODE (SET_SRC (element)) != PLUS
182      || ! REG_P (XEXP (SET_SRC (element), 0))
183      ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG
184      || ! CONST_INT_P (XEXP (SET_SRC (element), 1)))
185    return false;
186
187  /* Check that the next element is the first push.  */
188  element = XVECEXP (op, 0, 1);
189  if (   ! SET_P (element)
190      || ! REG_P (SET_DEST (element))
191      || ! MEM_P (SET_SRC (element))
192      || ! REG_P (XEXP (SET_SRC (element), 0))
193      ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG)
194    return false;
195
196  dest_regno = REGNO (SET_DEST (element));
197
198  /* Check that the remaining elements use SP+<disp>
199     addressing and incremental register numbers.  */
200  for (i = 2; i < count; i++)
201    {
202      element = XVECEXP (op, 0, i);
203
204      if (   ! SET_P (element)
205	  || ! REG_P (SET_DEST (element))
206	  || GET_MODE (SET_DEST (element)) != SImode
207	  || REGNO (SET_DEST (element)) != dest_regno + (i - 1)
208	  || ! MEM_P (SET_SRC (element))
209	  || GET_MODE (SET_SRC (element)) != SImode
210	  || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS
211          || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0))
212          ||   REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG
213	  || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1))
214	  || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1))
215	     != (i - 1) * GET_MODE_SIZE (SImode))
216	return false;
217    }
218  return true;
219})
220
221;; Return true if OP is a pop-and-return load multiple operation.
222;; This looks like:
223;;  [(set (SP) (PLUS (SP) (INT)))
224;;   (set (REG) (MEM (SP)))
225;;   (set (REG) (MEM (PLUS (SP) (INT)))) {optional and possibly repeated}
226;;   (return)
227;;  ]
228
229(define_special_predicate "rx_rtsd_vector"
230  (match_code "parallel")
231{
232  int count = XVECLEN (op, 0);
233  unsigned int dest_regno;
234  rtx element;
235  int i;
236
237  /* Perform a quick check so we don't blow up below.  */
238  if (count <= 2)
239    return false;
240
241  /* Check that the first element of the vector is the stack adjust.  */
242  element = XVECEXP (op, 0, 0);
243  if (   ! SET_P (element)
244      || ! REG_P (SET_DEST (element))
245      ||   REGNO (SET_DEST (element)) != SP_REG
246      ||   GET_CODE (SET_SRC (element)) != PLUS
247      || ! REG_P (XEXP (SET_SRC (element), 0))
248      ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG
249      || ! CONST_INT_P (XEXP (SET_SRC (element), 1)))
250    return false;
251
252  /* Check that the next element is the first push.  */
253  element = XVECEXP (op, 0, 1);
254  if (   ! SET_P (element)
255      || ! REG_P (SET_DEST (element))
256      || ! MEM_P (SET_SRC (element))
257      || ! REG_P (XEXP (SET_SRC (element), 0))
258      ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG)
259    return false;
260
261  dest_regno = REGNO (SET_DEST (element));
262
263  /* Check that the remaining elements, if any, and except
264     for the last one, use SP+<disp> addressing and incremental
265     register numbers.  */
266  for (i = 2; i < count - 1; i++)
267    {
268      element = XVECEXP (op, 0, i);
269
270      if (   ! SET_P (element)
271	  || ! REG_P (SET_DEST (element))
272	  || GET_MODE (SET_DEST (element)) != SImode
273	  || REGNO (SET_DEST (element)) != dest_regno + (i - 1)
274	  || ! MEM_P (SET_SRC (element))
275	  || GET_MODE (SET_SRC (element)) != SImode
276	  || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS
277          || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0))
278          ||   REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG
279	  || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1))
280	  || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1))
281	     != (i - 1) * GET_MODE_SIZE (SImode))
282	return false;
283    }
284
285  /* The last element must be a RETURN.  */
286  element = XVECEXP (op, 0, count - 1);
287  return GET_CODE (element) == RETURN;
288})
289
290(define_predicate "label_ref_operand"
291  (match_code "label_ref")
292)
293
294(define_predicate "rx_z_comparison_operator"
295  (match_code "eq,ne")
296)
297
298(define_predicate "rx_zs_comparison_operator"
299  (match_code "eq,ne,lt,ge")
300)
301
302;; GT and LE omitted due to operand swap required.
303(define_predicate "rx_fp_comparison_operator"
304  (match_code "eq,ne,lt,ge,ordered,unordered")
305)
306
307(define_predicate "rshift_operator"
308  (match_code "ashiftrt,lshiftrt")
309)
310