1;; Predicate definitions for TI PRU.
2;; Copyright (C) 2014-2022 Free Software Foundation, Inc.
3;; Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
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(define_predicate "const_1_operand"
22  (and (match_code "const_int")
23       (match_test "INTVAL (op) == 1")))
24
25; Note: Always pass a valid mode!
26(define_predicate "const_ubyte_operand"
27  (match_code "const_int")
28{
29  gcc_assert (mode != VOIDmode);
30  return IN_RANGE (INTVAL (op) & GET_MODE_MASK (mode), 0, 0xff);
31})
32
33(define_predicate "const_uhword_operand"
34  (match_code "const_int")
35{
36  gcc_assert (mode != VOIDmode);
37  return IN_RANGE (INTVAL (op) & GET_MODE_MASK (mode), 0, 0xffff);
38})
39
40; TRUE for comparisons we support.
41(define_predicate "pru_cmp_operator"
42  (match_code "eq,ne,leu,ltu,geu,gtu"))
43
44; TRUE for signed comparisons that need special handling for PRU.
45(define_predicate "pru_signed_cmp_operator"
46  (match_code "ge,gt,le,lt"))
47
48;; FP Comparisons handled by pru_expand_pru_compare.
49(define_predicate "pru_fp_comparison_operator"
50  (match_code "eq,ne,lt,gt,le,ge"))
51
52;; Return true if OP is a constant that contains only one 1 in its
53;; binary representation.
54(define_predicate "single_one_operand"
55  (and (match_code "const_int")
56       (match_test "exact_log2 (INTVAL (op) & GET_MODE_MASK (mode)) >= 0")))
57
58;; Return true if OP is a constant that contains only one 0 in its
59;; binary representation.
60(define_predicate "single_zero_operand"
61  (and (match_code "const_int")
62       (match_test "exact_log2 (~INTVAL (op) & GET_MODE_MASK (mode)) >= 0")))
63
64(define_predicate "pru_muldst_operand"
65  (match_code "subreg,reg")
66{
67  if (register_operand (op, mode))
68    {
69      int regno;
70
71      if (REG_P (op))
72	regno = REGNO (op);
73      else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
74	regno = REGNO (SUBREG_REG (op));
75      else
76	return 0;
77
78      return REGNO_REG_CLASS (regno) == MULDST_REGS
79	     || regno >= FIRST_PSEUDO_REGISTER;
80    }
81  return 0;
82})
83
84(define_predicate "pru_mulsrc0_operand"
85  (match_code "subreg,reg")
86{
87  if (register_operand (op, mode))
88    {
89      int regno;
90
91      if (REG_P (op))
92	regno = REGNO (op);
93      else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
94	regno = REGNO (SUBREG_REG (op));
95      else
96	return 0;
97
98      return REGNO_REG_CLASS (regno) == MULSRC0_REGNUM
99	     || regno >= FIRST_PSEUDO_REGISTER;
100    }
101  return 0;
102})
103
104(define_predicate "pru_mulsrc1_operand"
105  (match_code "subreg,reg")
106{
107  if (register_operand (op, mode))
108    {
109      int regno;
110
111      if (REG_P (op))
112	regno = REGNO (op);
113      else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
114	regno = REGNO (SUBREG_REG (op));
115      else
116	return 0;
117
118      return REGNO_REG_CLASS (regno) == MULSRC1_REGNUM
119	     || regno >= FIRST_PSEUDO_REGISTER;
120    }
121  return 0;
122})
123
124(define_predicate "regio_operand"
125  (match_code "subreg,reg")
126{
127  if (register_operand (op, mode))
128    {
129      int regno;
130
131      if (REG_P (op))
132	regno = REGNO (op);
133      else if (GET_CODE (op) == SUBREG && REG_P (SUBREG_REG (op)))
134	regno = REGNO (SUBREG_REG (op));
135      else
136	return 0;
137
138      return REGNO_REG_CLASS (regno) == REGIO_REGS;
139    }
140  return 0;
141})
142
143(define_predicate "reg_or_const_int_operand"
144  (ior (match_operand 0 "const_int_operand")
145       (match_operand 0 "register_operand")))
146
147(define_predicate "reg_or_ubyte_operand"
148  (ior (match_operand 0 "const_ubyte_operand")
149       (match_operand 0 "register_operand")))
150
151(define_predicate "reg_or_const_1_operand"
152  (ior (match_operand 0 "const_1_operand")
153       (match_operand 0 "register_operand")))
154
155(define_predicate "const_shift_operand"
156  (and (match_code "const_int")
157       (match_test "SHIFT_INT (INTVAL (op))")))
158
159(define_predicate "shift_operand"
160  (ior (match_operand 0 "const_shift_operand")
161       (match_operand 0 "register_operand")))
162
163(define_predicate "ctable_addr_operand"
164  (and (match_code "const_int")
165       (match_test "pru_get_ctable_base_index (INTVAL (op)) >= 0")))
166
167(define_predicate "ctable_base_operand"
168  (and (match_code "const_int")
169       (match_test "pru_get_ctable_exact_base_index (INTVAL (op)) >= 0")))
170
171;; Ideally we should enforce a restriction to all text labels to fit in
172;; 16bits, as required by the PRU ISA.  But for the time being we'll rely on
173;; binutils to catch text segment overflows.
174(define_predicate "call_operand"
175  (ior (match_operand 0 "immediate_operand")
176       (match_operand 0 "register_operand")))
177
178;; Return true if OP is a text segment reference.
179;; This is needed for program memory address expressions.  Borrowed from AVR.
180(define_predicate "text_segment_operand"
181  (match_code "code_label,label_ref,symbol_ref,plus,minus")
182{
183  poly_int64 offset;
184  rtx base = strip_offset (op, &offset);
185
186  switch (GET_CODE (base))
187    {
188    case CODE_LABEL:
189      /* Why AVR lists this as a valid option?  Let's catch it.  */
190      gcc_unreachable ();
191      return false;
192    case LABEL_REF:
193      return true;
194    case SYMBOL_REF:
195      return SYMBOL_REF_FUNCTION_P (base);
196    case PLUS:
197    case MINUS:
198      /* Handle constructs like (&&label1 - &&label2).  See pr70460.c.  */
199      return text_segment_operand (XEXP (op, 0), VOIDmode);
200    default:
201      return false;
202    }
203})
204
205;; Return true if OP is a load multiple operation.  It is known to be a
206;; PARALLEL and the first section will be tested.
207
208(define_special_predicate "load_multiple_operation"
209  (match_code "parallel")
210{
211  machine_mode elt_mode;
212  int count = XVECLEN (op, 0);
213  unsigned int dest_regno;
214  rtx src_addr, base_reg;
215  poly_int64 base_offs;
216  int i;
217
218  /* Perform a quick check so we don't blow up below.  */
219  if (GET_CODE (XVECEXP (op, 0, 0)) != SET
220      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
221      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
222    return false;
223
224  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
225  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
226  elt_mode = GET_MODE (SET_DEST (XVECEXP (op, 0, 0)));
227
228  base_reg = strip_offset (src_addr, &base_offs);
229  if (GET_CODE (base_reg) != REG)
230    return false;
231
232  for (i = 1; i < count; i++)
233    {
234      rtx elt_reg;
235      poly_int64 elt_offs;
236      rtx elt = XVECEXP (op, 0, i);
237
238      if (GET_CODE (elt) != SET
239	  || GET_CODE (SET_DEST (elt)) != REG
240	  || GET_MODE (SET_DEST (elt)) != elt_mode
241	  || REGNO (SET_DEST (elt)) != dest_regno + i * GET_MODE_SIZE (elt_mode)
242	  || GET_CODE (SET_SRC (elt)) != MEM
243	  || GET_MODE (SET_SRC (elt)) != elt_mode)
244	return false;
245
246      elt_reg = strip_offset (XEXP (SET_SRC (elt), 0), &elt_offs);
247
248      if (GET_CODE (elt_reg) != REG
249	  || ! rtx_equal_p (elt_reg, base_reg)
250	  || elt_offs != base_offs + i * GET_MODE_SIZE (elt_mode))
251	return false;
252    }
253
254  return true;
255})
256
257;; Return true if OP is a store multiple operation.  It is known to be a
258;; PARALLEL and the first section will be tested.
259
260(define_special_predicate "store_multiple_operation"
261  (match_code "parallel")
262{
263  machine_mode elt_mode;
264  int count = XVECLEN (op, 0);
265  unsigned int src_regno;
266  rtx dest_addr, base_reg;
267  poly_int64 base_offs;
268  int i;
269
270  /* Perform a quick check so we don't blow up below.  */
271  if (GET_CODE (XVECEXP (op, 0, 0)) != SET
272      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
273      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
274    return false;
275
276  src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
277  dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
278  elt_mode = GET_MODE (SET_SRC (XVECEXP (op, 0, 0)));
279
280  base_reg = strip_offset (dest_addr, &base_offs);
281  if (GET_CODE (base_reg) != REG)
282    return false;
283
284  for (i = 1; i < count; i++)
285    {
286      rtx elt_reg;
287      poly_int64 elt_offs;
288      rtx elt = XVECEXP (op, 0, i);
289
290      if (GET_CODE (elt) != SET
291	  || GET_CODE (SET_SRC (elt)) != REG
292	  || GET_MODE (SET_SRC (elt)) != elt_mode
293	  || REGNO (SET_SRC (elt)) != src_regno + i * GET_MODE_SIZE (elt_mode)
294	  || GET_CODE (SET_DEST (elt)) != MEM
295	  || GET_MODE (SET_DEST (elt)) != elt_mode)
296	return false;
297
298      elt_reg = strip_offset (XEXP (SET_DEST (elt), 0), &elt_offs);
299
300      if (GET_CODE (elt_reg) != REG
301	  || ! rtx_equal_p (elt_reg, base_reg)
302	  || elt_offs != base_offs + i * GET_MODE_SIZE (elt_mode))
303	return false;
304    }
305  return true;
306})
307