1 | /* Generate code from machine description to perform peephole optimizations. |
2 | Copyright (C) 1987-2023 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GCC. |
5 | |
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 |
8 | Software Foundation; either version 3, or (at your option) any later |
9 | version. |
10 | |
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. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
19 | |
20 | |
21 | #include "bconfig.h" |
22 | #include "system.h" |
23 | #include "coretypes.h" |
24 | #include "tm.h" |
25 | #include "rtl.h" |
26 | #include "errors.h" |
27 | #include "gensupport.h" |
28 | |
29 | |
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 | |
43 | static int max_opno; |
44 | |
45 | /* Number of operands used in current peephole definition. */ |
46 | |
47 | static int n_operands; |
48 | |
49 | static void match_rtx (rtx, struct link *, int); |
50 | static void print_path (struct link *); |
51 | static void print_code (RTX_CODE); |
52 | |
53 | static void |
54 | gen_peephole (md_rtx_info *info) |
55 | { |
56 | rtx peep = info->def; |
57 | int ninsns = XVECLEN (peep, 0); |
58 | int i; |
59 | |
60 | n_operands = 0; |
61 | |
62 | printf (format: " insn = ins1;\n" ); |
63 | |
64 | for (i = 0; i < ninsns; i++) |
65 | { |
66 | if (i > 0) |
67 | { |
68 | printf (format: " do { insn = NEXT_INSN (insn);\n" ); |
69 | printf (format: " if (insn == 0) goto L%d; }\n" , info->index); |
70 | printf (format: " while (NOTE_P (insn)\n" ); |
71 | printf (format: "\t || (NONJUMP_INSN_P (insn)\n" ); |
72 | printf (format: "\t && (GET_CODE (PATTERN (insn)) == USE\n" ); |
73 | printf (format: "\t\t || GET_CODE (PATTERN (insn)) == CLOBBER)));\n" ); |
74 | |
75 | printf (format: " if (LABEL_P (insn)\n\ |
76 | || BARRIER_P (insn))\n goto L%d;\n" , info->index); |
77 | } |
78 | |
79 | printf (format: " pat = PATTERN (insn);\n" ); |
80 | |
81 | /* Walk the insn's pattern, remembering at all times the path |
82 | down to the walking point. */ |
83 | |
84 | match_rtx (XVECEXP (peep, 0, i), NULL, info->index); |
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 (format: " if (! (%s)) goto L%d;\n" , |
92 | XSTR (peep, 1), info->index); |
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 | |
100 | printf (format: " PATTERN (ins1) = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (%d, operands));\n" , n_operands); |
101 | |
102 | /* Record this define_peephole's insn code in the insn, |
103 | as if it had been recognized to match this. */ |
104 | printf (format: " INSN_CODE (ins1) = %d;\n" , info->index); |
105 | |
106 | /* Delete the remaining insns. */ |
107 | if (ninsns > 1) |
108 | printf (format: " delete_for_peephole (NEXT_INSN (ins1), insn);\n" ); |
109 | |
110 | /* See reload1.cc for insertion of NOTE which guarantees that this |
111 | cannot be zero. */ |
112 | printf (format: " return NEXT_INSN (insn);\n" ); |
113 | |
114 | printf (format: " L%d:\n\n" , info->index); |
115 | } |
116 | |
117 | static void |
118 | match_rtx (rtx x, struct link *path, int fail_label) |
119 | { |
120 | RTX_CODE code; |
121 | int i; |
122 | int len; |
123 | const char *fmt; |
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 (format: " x = " ); |
141 | print_path (path); |
142 | printf (format: ";\n" ); |
143 | |
144 | printf (format: " operands[%d] = x;\n" , XINT (x, 0)); |
145 | if (XSTR (x, 1) && XSTR (x, 1)[0]) |
146 | printf (format: " 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: |
151 | case MATCH_PAR_DUP: |
152 | printf (format: " x = " ); |
153 | print_path (path); |
154 | printf (format: ";\n" ); |
155 | |
156 | printf (format: " 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 (format: " x = " ); |
162 | print_path (path); |
163 | printf (format: ";\n" ); |
164 | |
165 | printf (format: " if (GET_CODE (operands[%d]) != GET_CODE (x)\n" , XINT (x, 0)); |
166 | printf (format: " || GET_MODE (operands[%d]) != GET_MODE (x)) goto L%d;\n" , |
167 | XINT (x, 0), fail_label); |
168 | printf (format: " 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), path: &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 (format: " x = " ); |
185 | print_path (path); |
186 | printf (format: ";\n" ); |
187 | |
188 | printf (format: " operands[%d] = x;\n" , XINT (x, 0)); |
189 | if (XSTR (x, 1) && XSTR (x, 1)[0]) |
190 | printf (format: " 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), path: &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 (format: " x = " ); |
208 | print_path (path); |
209 | printf (format: ";\n" ); |
210 | |
211 | printf (format: " if (GET_CODE (x) != PARALLEL) goto L%d;\n" , fail_label); |
212 | printf (format: " operands[%d] = x;\n" , XINT (x, 0)); |
213 | if (XSTR (x, 1) && XSTR (x, 1)[0]) |
214 | printf (format: " 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), path: &link, fail_label); |
222 | } |
223 | return; |
224 | |
225 | default: |
226 | break; |
227 | } |
228 | |
229 | printf (format: " x = " ); |
230 | print_path (path); |
231 | printf (format: ";\n" ); |
232 | |
233 | printf (format: " if (GET_CODE (x) != " ); |
234 | print_code (code); |
235 | printf (format: ") goto L%d;\n" , fail_label); |
236 | |
237 | if (GET_MODE (x) != VOIDmode) |
238 | { |
239 | printf (format: " 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), path: &link, fail_label); |
252 | else if (fmt[i] == 'E') |
253 | { |
254 | int j; |
255 | printf (format: " if (XVECLEN (x, %d) != %d) goto L%d;\n" , |
256 | i, XVECLEN (x, i), fail_label); |
257 | for (j = 0; j < XVECLEN (x, i); j++) |
258 | { |
259 | link.vecelt = j; |
260 | match_rtx (XVECEXP (x, i, j), path: &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 (format: " x = " ); |
269 | print_path (path); |
270 | printf (format: ";\n" ); |
271 | } |
272 | |
273 | printf (format: " if (XINT (x, %d) != %d) goto L%d;\n" , |
274 | i, XINT (x, i), fail_label); |
275 | } |
276 | else if (fmt[i] == 'r') |
277 | { |
278 | gcc_assert (i == 0); |
279 | printf (format: " if (REGNO (x) != %d) goto L%d;\n" , |
280 | REGNO (x), fail_label); |
281 | } |
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 (format: " x = " ); |
288 | print_path (path); |
289 | printf (format: ";\n" ); |
290 | } |
291 | |
292 | printf (format: " if (XWINT (x, %d) != " , i); |
293 | printf (HOST_WIDE_INT_PRINT_DEC, XWINT (x, i)); |
294 | printf (format: ") goto L%d;\n" , fail_label); |
295 | } |
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 (format: " x = " ); |
302 | print_path (path); |
303 | printf (format: ";\n" ); |
304 | } |
305 | |
306 | printf (format: " if (strcmp (XSTR (x, %d), \"%s\")) goto L%d;\n" , |
307 | i, XSTR (x, i), fail_label); |
308 | } |
309 | else if (fmt[i] == 'p') |
310 | /* Not going to support subregs for legacy define_peeholes. */ |
311 | gcc_unreachable (); |
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 |
320 | print_path (struct link *path) |
321 | { |
322 | if (path == 0) |
323 | printf (format: "pat" ); |
324 | else if (path->vecelt >= 0) |
325 | { |
326 | printf (format: "XVECEXP (" ); |
327 | print_path (path: path->next); |
328 | printf (format: ", %d, %d)" , path->pos, path->vecelt); |
329 | } |
330 | else |
331 | { |
332 | printf (format: "XEXP (" ); |
333 | print_path (path: path->next); |
334 | printf (format: ", %d)" , path->pos); |
335 | } |
336 | } |
337 | |
338 | static void |
339 | print_code (RTX_CODE code) |
340 | { |
341 | const char *p1; |
342 | for (p1 = GET_RTX_NAME (code); *p1; p1++) |
343 | putchar (TOUPPER (*p1)); |
344 | } |
345 | |
346 | extern int main (int, const char **); |
347 | |
348 | int |
349 | main (int argc, const char **argv) |
350 | { |
351 | max_opno = -1; |
352 | |
353 | progname = "genpeep" ; |
354 | |
355 | if (!init_rtx_reader_args (argc, argv)) |
356 | return (FATAL_EXIT_CODE); |
357 | |
358 | printf (format: "/* Generated automatically by the program `genpeep'\n\ |
359 | from the machine description file `md'. */\n\n" ); |
360 | |
361 | printf (format: "#define IN_TARGET_CODE 1\n" ); |
362 | printf (format: "#include \"config.h\"\n" ); |
363 | printf (format: "#include \"system.h\"\n" ); |
364 | printf (format: "#include \"coretypes.h\"\n" ); |
365 | printf (format: "#include \"backend.h\"\n" ); |
366 | printf (format: "#include \"tree.h\"\n" ); |
367 | printf (format: "#include \"rtl.h\"\n" ); |
368 | printf (format: "#include \"insn-config.h\"\n" ); |
369 | printf (format: "#include \"alias.h\"\n" ); |
370 | printf (format: "#include \"varasm.h\"\n" ); |
371 | printf (format: "#include \"stor-layout.h\"\n" ); |
372 | printf (format: "#include \"calls.h\"\n" ); |
373 | printf (format: "#include \"memmodel.h\"\n" ); |
374 | printf (format: "#include \"tm_p.h\"\n" ); |
375 | printf (format: "#include \"regs.h\"\n" ); |
376 | printf (format: "#include \"output.h\"\n" ); |
377 | printf (format: "#include \"recog.h\"\n" ); |
378 | printf (format: "#include \"except.h\"\n" ); |
379 | printf (format: "#include \"diagnostic-core.h\"\n" ); |
380 | printf (format: "#include \"flags.h\"\n" ); |
381 | printf (format: "#include \"tm-constrs.h\"\n\n" ); |
382 | |
383 | printf (format: "extern rtx peep_operand[];\n\n" ); |
384 | printf (format: "#define operands peep_operand\n\n" ); |
385 | |
386 | printf (format: "rtx_insn *\npeephole (rtx_insn *ins1)\n{\n" ); |
387 | printf (format: " rtx_insn *insn ATTRIBUTE_UNUSED;\n" ); |
388 | printf (format: " rtx x ATTRIBUTE_UNUSED, pat ATTRIBUTE_UNUSED;\n\n" ); |
389 | |
390 | /* Early out: no peepholes for insns followed by barriers. */ |
391 | printf (format: " if (NEXT_INSN (ins1)\n" ); |
392 | printf (format: " && BARRIER_P (NEXT_INSN (ins1)))\n" ); |
393 | printf (format: " return 0;\n\n" ); |
394 | |
395 | /* Read the machine description. */ |
396 | |
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: &info); |
403 | break; |
404 | |
405 | default: |
406 | break; |
407 | } |
408 | |
409 | printf (format: " return 0;\n}\n\n" ); |
410 | |
411 | if (max_opno == -1) |
412 | max_opno = 1; |
413 | |
414 | printf (format: "rtx peep_operand[%d];\n" , max_opno + 1); |
415 | |
416 | fflush (stdout); |
417 | return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); |
418 | } |
419 | |