]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/genpreds.c
genpreds.c: Add capability to generate predicate bodies as well as function prototypes.
[thirdparty/gcc.git] / gcc / genpreds.c
1 /* Generate from machine description:
2 - prototype declarations for operand predicates (tm-preds.h)
3 - function definitions of operand predicates, if defined new-style
4 (insn-preds.c)
5 Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
6
7 This file is part of GCC.
8
9 GCC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 GCC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING. If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
23
24 #include "bconfig.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "tm.h"
28 #include "rtl.h"
29 #include "errors.h"
30 #include "gensupport.h"
31 #include "obstack.h"
32
33 /* The new way to declare predicates is with (define_predicate) or
34 (define_special_predicate) expressions in the machine description.
35 This provides a function body as well as a name. */
36 static void
37 process_define_predicate (rtx defn)
38 {
39 struct pred_data *pred;
40 if (XEXP (defn, 1) == 0)
41 {
42 error ("%s: must give a predicate expression", XSTR (defn, 0));
43 return;
44 }
45
46 pred = xcalloc (sizeof (struct pred_data), 1);
47 pred->name = XSTR (defn, 0);
48 pred->exp = XEXP (defn, 1);
49 pred->c_block = XSTR (defn, 2);
50
51 if (GET_CODE (defn) == DEFINE_SPECIAL_PREDICATE)
52 pred->special = true;
53
54 add_predicate (pred);
55 }
56
57 /* Write tm-preds.h. Unfortunately, it is impossible to forward-declare
58 an enumeration in portable C, so we have to condition all these
59 prototypes on HAVE_MACHINE_MODES. */
60 static void
61 write_tm_preds_h (void)
62 {
63 struct pred_data *p;
64
65 printf ("\
66 /* Generated automatically by the program '%s'\n\
67 from the machine description file '%s'. */\n\n", progname, in_fname);
68
69 puts ("\
70 #ifndef GCC_TM_PREDS_H\n\
71 #define GCC_TM_PREDS_H\n\
72 \n\
73 #ifdef HAVE_MACHINE_MODES");
74
75 FOR_ALL_PREDICATES (p)
76 printf ("extern int %s (rtx, enum machine_mode);\n", p->name);
77
78 puts ("\
79 #endif /* HAVE_MACHINE_MODES */\n\
80 #endif /* tm-preds.h */");
81 }
82
83 /* Given a predicate, if it has an embedded C block, write the block
84 out as a static inline subroutine, and augment the RTL test with a
85 match_test that calls that subroutine. For instance,
86
87 (define_predicate "basereg_operand"
88 (match_operand 0 "register_operand")
89 {
90 if (GET_CODE (op) == SUBREG)
91 op = SUBREG_REG (op);
92 return REG_POINTER (op);
93 })
94
95 becomes
96
97 static inline int basereg_operand_1(rtx op, enum machine_mode mode)
98 {
99 if (GET_CODE (op) == SUBREG)
100 op = SUBREG_REG (op);
101 return REG_POINTER (op);
102 }
103
104 (define_predicate "basereg_operand"
105 (and (match_operand 0 "register_operand")
106 (match_test "basereg_operand_1 (op, mode)")))
107
108 The only wart is that there's no way to insist on a { } string in
109 an RTL template, so we have to handle "" strings. */
110
111
112 static void
113 write_predicate_subfunction (struct pred_data *p)
114 {
115 const char *match_test_str;
116 rtx match_test_exp, and_exp;
117
118 if (p->c_block[0] == '\0')
119 return;
120
121 /* Construct the function-call expression. */
122 obstack_grow (rtl_obstack, p->name, strlen (p->name));
123 obstack_grow (rtl_obstack, "_1 (op, mode)",
124 sizeof "_1 (op, mode)");
125 match_test_str = obstack_finish (rtl_obstack);
126
127 /* Add the function-call expression to the complete expression to be
128 evaluated. */
129 match_test_exp = rtx_alloc (MATCH_TEST);
130 XSTR (match_test_exp, 0) = match_test_str;
131
132 and_exp = rtx_alloc (AND);
133 XEXP (and_exp, 0) = p->exp;
134 XEXP (and_exp, 1) = match_test_exp;
135
136 p->exp = and_exp;
137
138 printf ("static inline int\n"
139 "%s_1 (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n",
140 p->name);
141 if (p->c_block[0] == '{')
142 fputs (p->c_block, stdout);
143 else
144 printf ("{\n %s\n}", p->c_block);
145 fputs ("\n\n", stdout);
146 }
147
148 /* Given an RTL expression EXP, find all subexpressions which we may
149 assume to perform mode tests. Normal MATCH_OPERAND does;
150 MATCH_CODE does if and only if it accepts CONST_INT or
151 CONST_DOUBLE; and we have to assume that MATCH_TEST does not.
152 These combine in almost-boolean fashion - the only exception is
153 that (not X) must be assumed not to perform a mode test, whether or
154 not X does.
155
156 The mark is the RTL /v flag, which is true for subexpressions which
157 do *not* perform mode tests.
158 */
159 #define NO_MODE_TEST(EXP) RTX_FLAG (EXP, volatil)
160 static void
161 mark_mode_tests (rtx exp)
162 {
163 switch (GET_CODE (exp))
164 {
165 case MATCH_OPERAND:
166 {
167 struct pred_data *p = lookup_predicate (XSTR (exp, 1));
168 if (!p)
169 error ("reference to undefined predicate '%s'", XSTR (exp, 1));
170 else if (p->special)
171 NO_MODE_TEST (exp) = 1;
172 }
173 break;
174
175 case MATCH_CODE:
176 if (!strstr (XSTR (exp, 0), "const_int")
177 && !strstr (XSTR (exp, 0), "const_double"))
178 NO_MODE_TEST (exp) = 1;
179 break;
180
181 case MATCH_TEST:
182 case NOT:
183 NO_MODE_TEST (exp) = 1;
184 break;
185
186 case AND:
187 mark_mode_tests (XEXP (exp, 0));
188 mark_mode_tests (XEXP (exp, 1));
189
190 NO_MODE_TEST (exp) = (NO_MODE_TEST (XEXP (exp, 0))
191 && NO_MODE_TEST (XEXP (exp, 1)));
192 break;
193
194 case IOR:
195 mark_mode_tests (XEXP (exp, 0));
196 mark_mode_tests (XEXP (exp, 1));
197
198 NO_MODE_TEST (exp) = (NO_MODE_TEST (XEXP (exp, 0))
199 || NO_MODE_TEST (XEXP (exp, 1)));
200 break;
201
202 case IF_THEN_ELSE:
203 /* A ? B : C does a mode test if (one of A and B) does a mode
204 test, and C does too. */
205 mark_mode_tests (XEXP (exp, 0));
206 mark_mode_tests (XEXP (exp, 1));
207 mark_mode_tests (XEXP (exp, 2));
208
209 NO_MODE_TEST (exp) = ((NO_MODE_TEST (XEXP (exp, 0))
210 && NO_MODE_TEST (XEXP (exp, 1)))
211 || NO_MODE_TEST (XEXP (exp, 2)));
212 break;
213
214 default:
215 error ("'%s' cannot be used in a define_predicate expression",
216 GET_RTX_NAME (GET_CODE (exp)));
217 }
218 }
219
220 /* Given a predicate, work out where in its RTL expression to add
221 tests for proper modes. Special predicates do not get any such
222 tests. We try to avoid adding tests when we don't have to; in
223 particular, other normal predicates can be counted on to do it for
224 us. */
225
226 static void
227 add_mode_tests (struct pred_data *p)
228 {
229 rtx match_test_exp, and_exp;
230 rtx *pos;
231
232 /* Don't touch special predicates. */
233 if (p->special)
234 return;
235
236 mark_mode_tests (p->exp);
237
238 /* If the whole expression already tests the mode, we're done. */
239 if (!NO_MODE_TEST (p->exp))
240 return;
241
242 match_test_exp = rtx_alloc (MATCH_TEST);
243 XSTR (match_test_exp, 0) = "mode == VOIDmode || GET_MODE (op) == mode";
244 and_exp = rtx_alloc (AND);
245 XEXP (and_exp, 1) = match_test_exp;
246
247 /* It is always correct to rewrite p->exp as
248
249 (and (...) (match_test "mode == VOIDmode || GET_MODE (op) == mode"))
250
251 but there are a couple forms where we can do better. If the
252 top-level pattern is an IOR, and one of the two branches does test
253 the mode, we can wrap just the branch that doesn't. Likewise, if
254 we have an IF_THEN_ELSE, and one side of it tests the mode, we can
255 wrap just the side that doesn't. And, of course, we can repeat this
256 descent as many times as it works. */
257
258 pos = &p->exp;
259 for (;;)
260 {
261 rtx subexp = *pos;
262 if (GET_CODE (subexp) == IOR)
263 {
264 if (NO_MODE_TEST (XEXP (subexp, 0))
265 && NO_MODE_TEST (XEXP (subexp, 1)))
266 break;
267 else if (NO_MODE_TEST (XEXP (subexp, 0)))
268 pos = &XEXP (subexp, 0);
269 else if (NO_MODE_TEST (XEXP (subexp, 1)))
270 pos = &XEXP (subexp, 1);
271 else
272 abort ();
273 }
274 else if (GET_CODE (subexp) == IF_THEN_ELSE)
275 {
276 if (NO_MODE_TEST (XEXP (subexp, 0))
277 && NO_MODE_TEST (XEXP (subexp, 1))
278 && NO_MODE_TEST (XEXP (subexp, 2)))
279 break;
280 else if (NO_MODE_TEST (XEXP (subexp, 0))
281 && NO_MODE_TEST (XEXP (subexp, 1)))
282 /* Must put it on the dependent clause, not the controlling
283 expression, or we change the meaning of the test. */
284 pos = &XEXP (subexp, 1);
285 else if (NO_MODE_TEST (XEXP (subexp, 2)))
286 pos = &XEXP (subexp, 2);
287 else
288 abort ();
289 }
290 else
291 break;
292 }
293
294 XEXP (and_exp, 0) = *pos;
295 *pos = and_exp;
296 }
297
298
299 /* CODES is a list of RTX codes. Write out an expression which
300 determines whether the operand has one of those codes. */
301 static void
302 write_match_code (const char *codes)
303 {
304 const char *code;
305
306 while ((code = scan_comma_elt (&codes)) != 0)
307 {
308 fputs ("GET_CODE (op) == ", stdout);
309 while (code < codes)
310 {
311 putchar (TOUPPER (*code));
312 code++;
313 }
314
315 if (*codes == ',')
316 fputs (" || ", stdout);
317 }
318 }
319
320 /* EXP is an RTL (sub)expression for a predicate. Recursively
321 descend the expression and write out an equivalent C expression. */
322 static void
323 write_predicate_expr (const char *name, rtx exp)
324 {
325 switch (GET_CODE (exp))
326 {
327 case AND:
328 putchar ('(');
329 write_predicate_expr (name, XEXP (exp, 0));
330 fputs (") && (", stdout);
331 write_predicate_expr (name, XEXP (exp, 1));
332 putchar (')');
333 break;
334
335 case IOR:
336 putchar ('(');
337 write_predicate_expr (name, XEXP (exp, 0));
338 fputs (") || (", stdout);
339 write_predicate_expr (name, XEXP (exp, 1));
340 putchar (')');
341 break;
342
343 case NOT:
344 fputs ("!(", stdout);
345 write_predicate_expr (name, XEXP (exp, 0));
346 putchar (')');
347 break;
348
349 case IF_THEN_ELSE:
350 putchar ('(');
351 write_predicate_expr (name, XEXP (exp, 0));
352 fputs (") ? (", stdout);
353 write_predicate_expr (name, XEXP (exp, 1));
354 fputs (") : (", stdout);
355 write_predicate_expr (name, XEXP (exp, 2));
356 putchar (')');
357 break;
358
359 case MATCH_OPERAND:
360 printf ("%s (op, mode)", XSTR (exp, 1));
361 break;
362
363 case MATCH_CODE:
364 write_match_code (XSTR (exp, 0));
365 break;
366
367 case MATCH_TEST:
368 fputs (XSTR (exp, 0), stdout);
369 break;
370
371 default:
372 error ("%s: cannot use '%s' in a predicate expression",
373 name, GET_RTX_NAME (GET_CODE (exp)));
374 putchar ('0');
375 }
376 }
377
378 /* Given a predicate, write out a complete C function to compute it. */
379 static void
380 write_one_predicate_function (struct pred_data *p)
381 {
382 if (!p->exp)
383 return;
384
385 write_predicate_subfunction (p);
386 add_mode_tests (p);
387
388 /* A normal predicate can legitimately not look at enum machine_mode
389 if it accepts only CONST_INTs and/or CONST_DOUBLEs. */
390 printf ("int\n%s (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n"
391 "{\n return ",
392 p->name);
393 write_predicate_expr (p->name, p->exp);
394 fputs (";\n}\n\n", stdout);
395 }
396
397 /* Write insn-preds.c.
398 N.B. the list of headers to include was copied from genrecog; it
399 may not be ideal.
400
401 FUTURE: Write #line markers referring back to the machine
402 description. (Can't practically do this now since we don't know
403 the line number of the C block - just the line number of the enclosing
404 expression.) */
405 static void
406 write_insn_preds_c (void)
407 {
408 struct pred_data *p;
409
410 printf ("\
411 /* Generated automatically by the program '%s'\n\
412 from the machine description file '%s'. */\n\n", progname, in_fname);
413
414 puts ("\
415 #include \"config.h\"\n\
416 #include \"system.h\"\n\
417 #include \"coretypes.h\"\n\
418 #include \"tm.h\"\n\
419 #include \"rtl.h\"\n\
420 #include \"tm_p.h\"\n\
421 #include \"function.h\"\n\
422 #include \"insn-config.h\"\n\
423 #include \"recog.h\"\n\
424 #include \"real.h\"\n\
425 #include \"output.h\"\n\
426 #include \"flags.h\"\n\
427 #include \"hard-reg-set.h\"\n\
428 #include \"resource.h\"\n\
429 #include \"toplev.h\"\n\
430 #include \"reload.h\"\n");
431
432 FOR_ALL_PREDICATES (p)
433 write_one_predicate_function (p);
434 }
435
436 /* Argument parsing. */
437 static bool gen_header;
438 static bool
439 parse_option (const char *opt)
440 {
441 if (!strcmp (opt, "-h"))
442 {
443 gen_header = true;
444 return 1;
445 }
446 else
447 return 0;
448 }
449
450 /* Master control. */
451 int
452 main (int argc, char **argv)
453 {
454 rtx defn;
455 int pattern_lineno, next_insn_code = 0;
456
457 progname = argv[0];
458 if (argc <= 1)
459 fatal ("no input file name");
460 if (init_md_reader_args_cb (argc, argv, parse_option) != SUCCESS_EXIT_CODE)
461 return FATAL_EXIT_CODE;
462
463 while ((defn = read_md_rtx (&pattern_lineno, &next_insn_code)) != 0)
464 {
465 if (GET_CODE (defn) == DEFINE_PREDICATE
466 || GET_CODE (defn) == DEFINE_SPECIAL_PREDICATE)
467 process_define_predicate (defn);
468 }
469
470 if (gen_header)
471 write_tm_preds_h ();
472 else
473 write_insn_preds_c ();
474
475 if (have_error || ferror (stdout) || fflush (stdout) || fclose (stdout))
476 return FATAL_EXIT_CODE;
477
478 return SUCCESS_EXIT_CODE;
479 }
480
481 /* Dummy for debugging purposes. */
482 const char *
483 get_insn_name (int code ATTRIBUTE_UNUSED)
484 {
485 return 0;
486 }