]>
Commit | Line | Data |
---|---|---|
8d2af3a2 | 1 | ;; Predicate definitions for TI PRU. |
7adcbafe | 2 | ;; Copyright (C) 2014-2022 Free Software Foundation, Inc. |
8d2af3a2 DD |
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 | ||
8bafc964 DD |
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 | ||
8d2af3a2 DD |
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 | }) |