]>
Commit | Line | Data |
---|---|---|
ac7aba6e | 1 | /* Generate code from machine description to perform peephole optimizations. |
aad93da1 | 2 | Copyright (C) 1987-2017 Free Software Foundation, Inc. |
ac7aba6e | 3 | |
f12b58b3 | 4 | This file is part of GCC. |
ac7aba6e | 5 | |
f12b58b3 | 6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free | |
8c4c00c1 | 8 | Software Foundation; either version 3, or (at your option) any later |
f12b58b3 | 9 | version. |
ac7aba6e | 10 | |
f12b58b3 | 11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | for more details. | |
ac7aba6e | 15 | |
16 | You should have received a copy of the GNU General Public License | |
8c4c00c1 | 17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ | |
ac7aba6e | 19 | |
20 | ||
805e22b2 | 21 | #include "bconfig.h" |
5ce88198 | 22 | #include "system.h" |
805e22b2 | 23 | #include "coretypes.h" |
24 | #include "tm.h" | |
ac7aba6e | 25 | #include "rtl.h" |
04b58880 | 26 | #include "errors.h" |
c5ddd6b5 | 27 | #include "gensupport.h" |
ac7aba6e | 28 | |
ac7aba6e | 29 | |
ac7aba6e | 30 | /* While tree-walking an instruction pattern, we keep a chain |
31 | of these `struct link's to record how to get down to the | |
32 | current position. In each one, POS is the operand number, | |
33 | and if the operand is a vector VEC is the element number. | |
34 | VEC is -1 if the operand is not a vector. */ | |
35 | ||
36 | struct link | |
37 | { | |
38 | struct link *next; | |
39 | int pos; | |
40 | int vecelt; | |
41 | }; | |
42 | ||
ac7aba6e | 43 | static int max_opno; |
44 | ||
45 | /* Number of operands used in current peephole definition. */ | |
46 | ||
47 | static int n_operands; | |
48 | ||
1a97be37 | 49 | static void match_rtx (rtx, struct link *, int); |
50 | static void print_path (struct link *); | |
51 | static void print_code (RTX_CODE); | |
ac7aba6e | 52 | \f |
53 | static void | |
c04601c1 | 54 | gen_peephole (md_rtx_info *info) |
ac7aba6e | 55 | { |
c04601c1 | 56 | rtx peep = info->def; |
ac7aba6e | 57 | int ninsns = XVECLEN (peep, 0); |
58 | int i; | |
59 | ||
60 | n_operands = 0; | |
61 | ||
62 | printf (" insn = ins1;\n"); | |
ac7aba6e | 63 | |
64 | for (i = 0; i < ninsns; i++) | |
65 | { | |
66 | if (i > 0) | |
67 | { | |
68 | printf (" do { insn = NEXT_INSN (insn);\n"); | |
c04601c1 | 69 | printf (" if (insn == 0) goto L%d; }\n", info->index); |
6d7dc5b9 | 70 | printf (" while (NOTE_P (insn)\n"); |
71 | printf ("\t || (NONJUMP_INSN_P (insn)\n"); | |
ac7aba6e | 72 | printf ("\t && (GET_CODE (PATTERN (insn)) == USE\n"); |
73 | printf ("\t\t || GET_CODE (PATTERN (insn)) == CLOBBER)));\n"); | |
74 | ||
6d7dc5b9 | 75 | printf (" if (LABEL_P (insn)\n\ |
c04601c1 | 76 | || BARRIER_P (insn))\n goto L%d;\n", info->index); |
ac7aba6e | 77 | } |
78 | ||
ac7aba6e | 79 | printf (" pat = PATTERN (insn);\n"); |
80 | ||
81 | /* Walk the insn's pattern, remembering at all times the path | |
82 | down to the walking point. */ | |
83 | ||
c04601c1 | 84 | match_rtx (XVECEXP (peep, 0, i), NULL, info->index); |
ac7aba6e | 85 | } |
86 | ||
87 | /* We get this far if the pattern matches. | |
88 | Now test the extra condition. */ | |
89 | ||
90 | if (XSTR (peep, 1) && XSTR (peep, 1)[0]) | |
91 | printf (" if (! (%s)) goto L%d;\n", | |
c04601c1 | 92 | XSTR (peep, 1), info->index); |
ac7aba6e | 93 | |
94 | /* If that matches, construct new pattern and put it in the first insn. | |
95 | This new pattern will never be matched. | |
96 | It exists only so that insn-extract can get the operands back. | |
97 | So use a simple regular form: a PARALLEL containing a vector | |
98 | of all the operands. */ | |
99 | ||
941522d6 | 100 | printf (" PATTERN (ins1) = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (%d, operands));\n", n_operands); |
ac7aba6e | 101 | |
ac7aba6e | 102 | /* Record this define_peephole's insn code in the insn, |
103 | as if it had been recognized to match this. */ | |
c04601c1 | 104 | printf (" INSN_CODE (ins1) = %d;\n", info->index); |
ac7aba6e | 105 | |
106 | /* Delete the remaining insns. */ | |
107 | if (ninsns > 1) | |
108 | printf (" delete_for_peephole (NEXT_INSN (ins1), insn);\n"); | |
109 | ||
110 | /* See reload1.c for insertion of NOTE which guarantees that this | |
111 | cannot be zero. */ | |
112 | printf (" return NEXT_INSN (insn);\n"); | |
113 | ||
c04601c1 | 114 | printf (" L%d:\n\n", info->index); |
ac7aba6e | 115 | } |
116 | \f | |
117 | static void | |
1a97be37 | 118 | match_rtx (rtx x, struct link *path, int fail_label) |
ac7aba6e | 119 | { |
19cb6b50 | 120 | RTX_CODE code; |
121 | int i; | |
122 | int len; | |
123 | const char *fmt; | |
ac7aba6e | 124 | struct link link; |
125 | ||
126 | if (x == 0) | |
127 | return; | |
128 | ||
129 | ||
130 | code = GET_CODE (x); | |
131 | ||
132 | switch (code) | |
133 | { | |
134 | case MATCH_OPERAND: | |
135 | if (XINT (x, 0) > max_opno) | |
136 | max_opno = XINT (x, 0); | |
137 | if (XINT (x, 0) >= n_operands) | |
138 | n_operands = 1 + XINT (x, 0); | |
139 | ||
140 | printf (" x = "); | |
141 | print_path (path); | |
142 | printf (";\n"); | |
143 | ||
144 | printf (" operands[%d] = x;\n", XINT (x, 0)); | |
145 | if (XSTR (x, 1) && XSTR (x, 1)[0]) | |
146 | printf (" if (! %s (x, %smode)) goto L%d;\n", | |
147 | XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label); | |
148 | return; | |
149 | ||
150 | case MATCH_DUP: | |
d920879a | 151 | case MATCH_PAR_DUP: |
ac7aba6e | 152 | printf (" x = "); |
153 | print_path (path); | |
154 | printf (";\n"); | |
155 | ||
156 | printf (" if (!rtx_equal_p (operands[%d], x)) goto L%d;\n", | |
157 | XINT (x, 0), fail_label); | |
158 | return; | |
159 | ||
160 | case MATCH_OP_DUP: | |
161 | printf (" x = "); | |
162 | print_path (path); | |
163 | printf (";\n"); | |
164 | ||
165 | printf (" if (GET_CODE (operands[%d]) != GET_CODE (x)\n", XINT (x, 0)); | |
166 | printf (" || GET_MODE (operands[%d]) != GET_MODE (x)) goto L%d;\n", | |
167 | XINT (x, 0), fail_label); | |
168 | printf (" operands[%d] = x;\n", XINT (x, 0)); | |
169 | link.next = path; | |
170 | link.vecelt = -1; | |
171 | for (i = 0; i < XVECLEN (x, 1); i++) | |
172 | { | |
173 | link.pos = i; | |
174 | match_rtx (XVECEXP (x, 1, i), &link, fail_label); | |
175 | } | |
176 | return; | |
177 | ||
178 | case MATCH_OPERATOR: | |
179 | if (XINT (x, 0) > max_opno) | |
180 | max_opno = XINT (x, 0); | |
181 | if (XINT (x, 0) >= n_operands) | |
182 | n_operands = 1 + XINT (x, 0); | |
183 | ||
184 | printf (" x = "); | |
185 | print_path (path); | |
186 | printf (";\n"); | |
187 | ||
188 | printf (" operands[%d] = x;\n", XINT (x, 0)); | |
189 | if (XSTR (x, 1) && XSTR (x, 1)[0]) | |
190 | printf (" if (! %s (x, %smode)) goto L%d;\n", | |
191 | XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label); | |
192 | link.next = path; | |
193 | link.vecelt = -1; | |
194 | for (i = 0; i < XVECLEN (x, 2); i++) | |
195 | { | |
196 | link.pos = i; | |
197 | match_rtx (XVECEXP (x, 2, i), &link, fail_label); | |
198 | } | |
199 | return; | |
200 | ||
201 | case MATCH_PARALLEL: | |
202 | if (XINT (x, 0) > max_opno) | |
203 | max_opno = XINT (x, 0); | |
204 | if (XINT (x, 0) >= n_operands) | |
205 | n_operands = 1 + XINT (x, 0); | |
206 | ||
207 | printf (" x = "); | |
208 | print_path (path); | |
209 | printf (";\n"); | |
210 | ||
211 | printf (" if (GET_CODE (x) != PARALLEL) goto L%d;\n", fail_label); | |
212 | printf (" operands[%d] = x;\n", XINT (x, 0)); | |
213 | if (XSTR (x, 1) && XSTR (x, 1)[0]) | |
214 | printf (" if (! %s (x, %smode)) goto L%d;\n", | |
215 | XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label); | |
216 | link.next = path; | |
217 | link.pos = 0; | |
218 | for (i = 0; i < XVECLEN (x, 2); i++) | |
219 | { | |
220 | link.vecelt = i; | |
221 | match_rtx (XVECEXP (x, 2, i), &link, fail_label); | |
222 | } | |
223 | return; | |
224 | ||
941522d6 | 225 | default: |
226 | break; | |
ac7aba6e | 227 | } |
228 | ||
229 | printf (" x = "); | |
230 | print_path (path); | |
231 | printf (";\n"); | |
232 | ||
233 | printf (" if (GET_CODE (x) != "); | |
234 | print_code (code); | |
235 | printf (") goto L%d;\n", fail_label); | |
236 | ||
237 | if (GET_MODE (x) != VOIDmode) | |
238 | { | |
239 | printf (" if (GET_MODE (x) != %smode) goto L%d;\n", | |
240 | GET_MODE_NAME (GET_MODE (x)), fail_label); | |
241 | } | |
242 | ||
243 | link.next = path; | |
244 | link.vecelt = -1; | |
245 | fmt = GET_RTX_FORMAT (code); | |
246 | len = GET_RTX_LENGTH (code); | |
247 | for (i = 0; i < len; i++) | |
248 | { | |
249 | link.pos = i; | |
250 | if (fmt[i] == 'e' || fmt[i] == 'u') | |
251 | match_rtx (XEXP (x, i), &link, fail_label); | |
252 | else if (fmt[i] == 'E') | |
253 | { | |
254 | int j; | |
255 | printf (" if (XVECLEN (x, %d) != %d) goto L%d;\n", | |
256 | i, XVECLEN (x, i), fail_label); | |
8de6412b | 257 | for (j = 0; j < XVECLEN (x, i); j++) |
ac7aba6e | 258 | { |
259 | link.vecelt = j; | |
260 | match_rtx (XVECEXP (x, i, j), &link, fail_label); | |
261 | } | |
262 | } | |
263 | else if (fmt[i] == 'i') | |
264 | { | |
265 | /* Make sure that at run time `x' is the RTX we want to test. */ | |
266 | if (i != 0) | |
267 | { | |
268 | printf (" x = "); | |
269 | print_path (path); | |
270 | printf (";\n"); | |
271 | } | |
272 | ||
273 | printf (" if (XINT (x, %d) != %d) goto L%d;\n", | |
274 | i, XINT (x, i), fail_label); | |
275 | } | |
15183fd2 | 276 | else if (fmt[i] == 'r') |
277 | { | |
278 | gcc_assert (i == 0); | |
279 | printf (" if (REGNO (x) != %d) goto L%d;\n", | |
280 | REGNO (x), fail_label); | |
281 | } | |
2e19ac3c | 282 | else if (fmt[i] == 'w') |
283 | { | |
284 | /* Make sure that at run time `x' is the RTX we want to test. */ | |
285 | if (i != 0) | |
286 | { | |
287 | printf (" x = "); | |
288 | print_path (path); | |
289 | printf (";\n"); | |
290 | } | |
291 | ||
13a0a8d8 | 292 | printf (" if (XWINT (x, %d) != ", i); |
293 | printf (HOST_WIDE_INT_PRINT_DEC, XWINT (x, i)); | |
294 | printf (") goto L%d;\n", fail_label); | |
2e19ac3c | 295 | } |
ac7aba6e | 296 | else if (fmt[i] == 's') |
297 | { | |
298 | /* Make sure that at run time `x' is the RTX we want to test. */ | |
299 | if (i != 0) | |
300 | { | |
301 | printf (" x = "); | |
302 | print_path (path); | |
303 | printf (";\n"); | |
304 | } | |
305 | ||
306 | printf (" if (strcmp (XSTR (x, %d), \"%s\")) goto L%d;\n", | |
307 | i, XSTR (x, i), fail_label); | |
308 | } | |
9edf7ea8 | 309 | else if (fmt[i] == 'p') |
310 | /* Not going to support subregs for legacy define_peeholes. */ | |
311 | gcc_unreachable (); | |
ac7aba6e | 312 | } |
313 | } | |
314 | ||
315 | /* Given a PATH, representing a path down the instruction's | |
316 | pattern from the root to a certain point, output code to | |
317 | evaluate to the rtx at that point. */ | |
318 | ||
319 | static void | |
1a97be37 | 320 | print_path (struct link *path) |
ac7aba6e | 321 | { |
322 | if (path == 0) | |
323 | printf ("pat"); | |
324 | else if (path->vecelt >= 0) | |
325 | { | |
326 | printf ("XVECEXP ("); | |
327 | print_path (path->next); | |
328 | printf (", %d, %d)", path->pos, path->vecelt); | |
329 | } | |
330 | else | |
331 | { | |
332 | printf ("XEXP ("); | |
333 | print_path (path->next); | |
334 | printf (", %d)", path->pos); | |
335 | } | |
336 | } | |
337 | \f | |
338 | static void | |
1a97be37 | 339 | print_code (RTX_CODE code) |
ac7aba6e | 340 | { |
19cb6b50 | 341 | const char *p1; |
ac7aba6e | 342 | for (p1 = GET_RTX_NAME (code); *p1; p1++) |
9af5ce0c | 343 | putchar (TOUPPER (*p1)); |
ac7aba6e | 344 | } |
ac7aba6e | 345 | |
16570c04 | 346 | extern int main (int, const char **); |
947491b7 | 347 | |
ac7aba6e | 348 | int |
16570c04 | 349 | main (int argc, const char **argv) |
ac7aba6e | 350 | { |
ac7aba6e | 351 | max_opno = -1; |
352 | ||
04b58880 | 353 | progname = "genpeep"; |
ac7aba6e | 354 | |
77ba95d0 | 355 | if (!init_rtx_reader_args (argc, argv)) |
c5ddd6b5 | 356 | return (FATAL_EXIT_CODE); |
ac7aba6e | 357 | |
ac7aba6e | 358 | printf ("/* Generated automatically by the program `genpeep'\n\ |
359 | from the machine description file `md'. */\n\n"); | |
360 | ||
785790dc | 361 | printf ("#define IN_TARGET_CODE 1\n"); |
ac7aba6e | 362 | printf ("#include \"config.h\"\n"); |
9aaa1fcc | 363 | printf ("#include \"system.h\"\n"); |
805e22b2 | 364 | printf ("#include \"coretypes.h\"\n"); |
9ef16211 | 365 | printf ("#include \"backend.h\"\n"); |
366 | printf ("#include \"tree.h\"\n"); | |
367 | printf ("#include \"rtl.h\"\n"); | |
4063e82c | 368 | printf ("#include \"insn-config.h\"\n"); |
b20a8bb4 | 369 | printf ("#include \"alias.h\"\n"); |
9ed99284 | 370 | printf ("#include \"varasm.h\"\n"); |
371 | printf ("#include \"stor-layout.h\"\n"); | |
372 | printf ("#include \"calls.h\"\n"); | |
ad7b10a2 | 373 | printf ("#include \"memmodel.h\"\n"); |
9721bc37 | 374 | printf ("#include \"tm_p.h\"\n"); |
ac7aba6e | 375 | printf ("#include \"regs.h\"\n"); |
376 | printf ("#include \"output.h\"\n"); | |
4063e82c | 377 | printf ("#include \"recog.h\"\n"); |
a014ec0f | 378 | printf ("#include \"except.h\"\n"); |
c18cb818 | 379 | printf ("#include \"diagnostic-core.h\"\n"); |
234f6557 | 380 | printf ("#include \"flags.h\"\n"); |
a014ec0f | 381 | printf ("#include \"tm-constrs.h\"\n\n"); |
ac7aba6e | 382 | |
383 | printf ("extern rtx peep_operand[];\n\n"); | |
384 | printf ("#define operands peep_operand\n\n"); | |
385 | ||
dc1b3216 | 386 | printf ("rtx_insn *\npeephole (rtx_insn *ins1)\n{\n"); |
2db825a4 | 387 | printf (" rtx_insn *insn ATTRIBUTE_UNUSED;\n"); |
388 | printf (" rtx x ATTRIBUTE_UNUSED, pat ATTRIBUTE_UNUSED;\n\n"); | |
ac7aba6e | 389 | |
390 | /* Early out: no peepholes for insns followed by barriers. */ | |
391 | printf (" if (NEXT_INSN (ins1)\n"); | |
6d7dc5b9 | 392 | printf (" && BARRIER_P (NEXT_INSN (ins1)))\n"); |
ac7aba6e | 393 | printf (" return 0;\n\n"); |
394 | ||
395 | /* Read the machine description. */ | |
396 | ||
c04601c1 | 397 | md_rtx_info info; |
398 | while (read_md_rtx (&info)) | |
399 | switch (GET_CODE (info.def)) | |
400 | { | |
401 | case DEFINE_PEEPHOLE: | |
402 | gen_peephole (&info); | |
ac7aba6e | 403 | break; |
ac7aba6e | 404 | |
c04601c1 | 405 | default: |
406 | break; | |
407 | } | |
ac7aba6e | 408 | |
409 | printf (" return 0;\n}\n\n"); | |
410 | ||
411 | if (max_opno == -1) | |
412 | max_opno = 1; | |
413 | ||
414 | printf ("rtx peep_operand[%d];\n", max_opno + 1); | |
415 | ||
416 | fflush (stdout); | |
947491b7 | 417 | return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); |
ac7aba6e | 418 | } |