]>
Commit | Line | Data |
---|---|---|
65a324b4 NC |
1 | ;; Predicate definitions for Renesas RX. |
2 | ;; Copyright (C) 2008, 2009 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 | (match_code "symbol_ref,reg") | |
28 | ) | |
29 | ||
30 | ;; For sibcall operations we can only use a symbolic address. | |
31 | ||
32 | (define_predicate "rx_symbolic_call_operand" | |
33 | (match_code "symbol_ref") | |
34 | ) | |
35 | ||
36 | ;; Check that the operand is suitable for a shift insn | |
37 | ;; Only small integers or a value in a register are permitted. | |
38 | ||
39 | (define_predicate "rx_shift_operand" | |
40 | (match_code "const_int,reg") | |
41 | { | |
42 | if (CONST_INT_P (op)) | |
43 | return IN_RANGE (INTVAL (op), 0, 31); | |
44 | return true; | |
45 | } | |
46 | ) | |
47 | ||
48 | ;; Check that the operand is suitable as the source operand | |
49 | ;; for a logic or arithmeitc instruction. Registers, integers | |
50 | ;; and a restricted subset of memory addresses are allowed. | |
51 | ||
52 | (define_predicate "rx_source_operand" | |
aea8fc97 | 53 | (match_code "const_int,const_double,const,symbol_ref,label_ref,reg,mem") |
65a324b4 | 54 | { |
aea8fc97 | 55 | if (CONSTANT_P (op)) |
65a324b4 NC |
56 | return rx_is_legitimate_constant (op); |
57 | ||
58 | if (! MEM_P (op)) | |
59 | return true; | |
60 | ||
61 | /* Do not allow size conversions whilst accessing memory. */ | |
62 | if (GET_MODE (op) != mode) | |
63 | return false; | |
64 | ||
65 | return rx_is_restricted_memory_address (XEXP (op, 0), mode); | |
66 | } | |
67 | ) | |
68 | ||
69 | ;; Check that the operand is suitable as the source operand | |
70 | ;; for a comparison instruction. This is the same as | |
71 | ;; rx_source_operand except that SUBREGs are allowed but | |
72 | ;; CONST_INTs are not. | |
73 | ||
74 | (define_predicate "rx_compare_operand" | |
75 | (match_code "subreg,reg,mem") | |
76 | { | |
77 | if (GET_CODE (op) == SUBREG) | |
78 | return REG_P (XEXP (op, 0)); | |
79 | ||
80 | if (! MEM_P (op)) | |
81 | return true; | |
82 | ||
83 | return rx_is_restricted_memory_address (XEXP (op, 0), mode); | |
84 | } | |
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) | |
9595a419 NC |
120 | || ! REG_P (SET_SRC (element)) |
121 | || GET_MODE (SET_SRC (element)) != SImode | |
65a324b4 | 122 | || ! MEM_P (SET_DEST (element)) |
9595a419 NC |
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)) | |
65a324b4 NC |
130 | return false; |
131 | ||
132 | src_regno = REGNO (SET_SRC (element)); | |
133 | ||
134 | /* Check that the remaining elements use SP-<disp> | |
9595a419 | 135 | addressing and decreasing register numbers. */ |
65a324b4 NC |
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 | |
9595a419 | 143 | || REGNO (SET_SRC (element)) != src_regno - (i - 1) |
65a324b4 NC |
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)) | |
9595a419 | 151 | != i * GET_MODE_SIZE (SImode)) |
65a324b4 NC |
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 | }) |