Import GCC-8 to a new vendor branch
[dragonfly.git] / contrib / gcc-8.0 / gcc / gentarget-def.c
1 /* Generate insn-target-def.h, an automatically-generated part of targetm.
2    Copyright (C) 1987-2018 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 #include "bconfig.h"
21 #include "system.h"
22 #include "coretypes.h"
23 #include "tm.h"
24 #include "rtl.h"
25 #include "errors.h"
26 #include "read-md.h"
27 #include "gensupport.h"
28 #include "hash-table.h"
29
30 /* This class hashes define_insns and define_expands by name.  */
31 struct insn_hasher : nofree_ptr_hash <rtx_def>
32 {
33   typedef rtx value_type;
34   typedef const char *compare_type;
35
36   static inline hashval_t hash (rtx);
37   static inline bool equal (rtx, const char *);
38 };
39
40 hashval_t
41 insn_hasher::hash (rtx x)
42 {
43   return htab_hash_string (XSTR (x, 0));
44 }
45
46 bool
47 insn_hasher::equal (rtx x, const char *y)
48 {
49   return strcmp (XSTR (x, 0), y) == 0;
50 }
51
52 /* All define_insns and define_expands, hashed by name.  */
53 static hash_table <insn_hasher> *insns;
54
55 /* Records the prototype suffix X for each invalid_X stub that has been
56    generated.  */
57 static hash_table <nofree_string_hash> *stubs;
58
59 /* Records which C conditions have been wrapped in functions, as a mapping
60    from the C condition to the function name.  */
61 static hash_map <nofree_string_hash, const char *> *have_funcs;
62
63 /* Return true if the part of the prototype at P is for an argument
64    name.  If so, point *END_OUT to the first character after the name.
65    If OPNO_OUT is nonnull, set *OPNO_OUT to the number of the associated
66    operand.  If REQUIRED_OUT is nonnull, set *REQUIRED_OUT to whether the
67    .md pattern is required to match the operand.  */
68
69 static bool
70 parse_argument (const char *p, const char **end_out,
71                 unsigned int *opno_out = 0,
72                 bool *required_out = 0)
73 {
74   while (ISSPACE (*p))
75     p++;
76   if (p[0] == 'x' && ISDIGIT (p[1]))
77     {
78       p += 1;
79       if (required_out)
80         *required_out = true;
81     }
82   else if (p[0] == 'o' && p[1] == 'p' && p[2] == 't' && ISDIGIT (p[3]))
83     {
84       p += 3;
85       if (required_out)
86         *required_out = false;
87     }
88   else
89     return false;
90
91   char *endptr;
92   unsigned int opno = strtol (p, &endptr, 10);
93   if (opno_out)
94     *opno_out = opno;
95   *end_out = endptr;
96   return true;
97 }
98
99
100 /* Output hook definitions for pattern NAME, which has target-insns.def
101    prototype PROTOTYPE.  */
102
103 static void
104 def_target_insn (const char *name, const char *prototype)
105 {
106   /* Get an upper-case form of NAME.  */
107   unsigned int i;
108   char *upper_name = XALLOCAVEC (char, strlen (name) + 1);
109   for (i = 0; name[i]; ++i)
110     upper_name[i] = TOUPPER (name[i]);
111   upper_name[i] = 0;
112
113   /* Check that the prototype is valid and concatenate the types
114      together to get a suffix.  */
115   char *suffix = XALLOCAVEC (char, strlen (prototype) + 1);
116   i = 0;
117   unsigned int opno = 0;
118   unsigned int required_ops = 0;
119   unsigned int this_opno;
120   bool required_p;
121   for (const char *p = prototype; *p; ++p)
122     if (parse_argument (p, &p, &this_opno, &required_p))
123       {
124         if (this_opno != opno || (*p != ',' && *p != ')'))
125           {
126             error ("invalid prototype for '%s'", name);
127             exit (FATAL_EXIT_CODE);
128           }
129         if (required_p && required_ops < opno)
130           {
131             error ("prototype for '%s' has required operands after"
132                    " optional operands", name);
133             exit (FATAL_EXIT_CODE);
134           }
135         opno += 1;
136         if (required_p)
137           required_ops = opno;
138         /* Skip over ')'s.  */
139         if (*p == ',')
140           suffix[i++] = '_';
141       }
142     else if (*p == ')' || *p == ',')
143       {
144         /* We found the end of a parameter without finding a
145            parameter name.  */
146         if (strcmp (prototype, "(void)") != 0)
147           {
148             error ("argument %d of '%s' did not have the expected name",
149                    opno, name);
150             exit (FATAL_EXIT_CODE);
151           }
152       }
153     else if (*p != '(' && !ISSPACE (*p))
154       suffix[i++] = *p;
155   suffix[i] = 0;
156
157   /* See whether we have an implementation of this pattern.  */
158   hashval_t hash = htab_hash_string (name);
159   int truth = 0;
160   const char *have_name = name;
161   if (rtx insn = insns->find_with_hash (name, hash))
162     {
163       pattern_stats stats;
164       get_pattern_stats (&stats, XVEC (insn, 1));
165       unsigned int actual_ops = stats.num_generator_args;
166       if (opno == required_ops && opno != actual_ops)
167         error_at (get_file_location (insn),
168                   "'%s' must have %d operands (excluding match_dups)",
169                   name, required_ops);
170       else if (actual_ops < required_ops)
171         error_at (get_file_location (insn),
172                   "'%s' must have at least %d operands (excluding match_dups)",
173                   name, required_ops);
174       else if (actual_ops > opno)
175         error_at (get_file_location (insn),
176                   "'%s' must have no more than %d operands"
177                   " (excluding match_dups)", name, opno);
178
179       const char *test = XSTR (insn, 2);
180       truth = maybe_eval_c_test (test);
181       gcc_assert (truth != 0);
182       if (truth < 0)
183         {
184           /* Try to reuse an existing function that performs the same test.  */
185           bool existed;
186           const char *&entry = have_funcs->get_or_insert (test, &existed);
187           if (!existed)
188             {
189               entry = name;
190               printf ("\nstatic bool\n");
191               printf ("target_have_%s (void)\n", name);
192               printf ("{\n");
193               printf ("  return ");
194               rtx_reader_ptr->print_c_condition (test);
195               printf (";\n");
196               printf ("}\n");
197             }
198           have_name = entry;
199         }
200       printf ("\nstatic rtx_insn *\n");
201       printf ("target_gen_%s ", name);
202       /* Print the prototype with the argument names after ACTUAL_OPS
203          removed.  */
204       const char *p = prototype, *end;
205       while (*p)
206         if (parse_argument (p, &end, &this_opno) && this_opno >= actual_ops)
207           p = end;
208         else
209           fputc (*p++, stdout);
210
211       printf ("\n{\n");
212       if (truth < 0)
213         printf ("  gcc_checking_assert (targetm.have_%s ());\n", name);
214       printf ("  return insnify (gen_%s (", name);
215       for (i = 0; i < actual_ops; ++i)
216         printf ("%s%s%d", i == 0 ? "" : ", ",
217                 i < required_ops ? "x" : "opt", i);
218       printf ("));\n");
219       printf ("}\n");
220     }
221   else
222     {
223       const char **slot = stubs->find_slot (suffix, INSERT);
224       if (!*slot)
225         {
226           *slot = xstrdup (suffix);
227           printf ("\nstatic rtx_insn *\n");
228           printf ("invalid_%s ", suffix);
229           /* Print the prototype with the argument names removed.  */
230           const char *p = prototype;
231           while (*p)
232             if (!parse_argument (p, &p))
233               fputc (*p++, stdout);
234           printf ("\n{\n");
235           printf ("  gcc_unreachable ();\n");
236           printf ("}\n");
237         }
238     }
239   printf ("\n#undef TARGET_HAVE_%s\n", upper_name);
240   printf ("#define TARGET_HAVE_%s ", upper_name);
241   if (truth == 0)
242     printf ("hook_bool_void_false\n");
243   else if (truth == 1)
244     printf ("hook_bool_void_true\n");
245   else
246     printf ("target_have_%s\n", have_name);
247
248   printf ("#undef TARGET_GEN_%s\n", upper_name);
249   printf ("#define TARGET_GEN_%s ", upper_name);
250   if (truth == 0)
251     printf ("invalid_%s\n", suffix);
252   else
253     printf ("target_gen_%s\n", name);
254
255   printf ("#undef TARGET_CODE_FOR_%s\n", upper_name);
256   printf ("#define TARGET_CODE_FOR_%s ", upper_name);
257   if (truth == 0)
258     printf ("CODE_FOR_nothing\n");
259   else
260     printf ("CODE_FOR_%s\n", name);
261 }
262
263 /* Record the DEFINE_INSN or DEFINE_EXPAND described by INFO.  */
264
265 static void
266 add_insn (md_rtx_info *info)
267 {
268   rtx def = info->def;
269   const char *name = XSTR (def, 0);
270   if (name[0] == 0 || name[0] == '*')
271     return;
272
273   hashval_t hash = htab_hash_string (name);
274   rtx *slot = insns->find_slot_with_hash (name, hash, INSERT);
275   if (*slot)
276     error_at (info->loc, "duplicate definition of '%s'", name);
277   else
278     *slot = def;
279 }
280
281 int
282 main (int argc, const char **argv)
283 {
284   progname = "gentarget-def";
285
286   if (!init_rtx_reader_args (argc, argv))
287     return (FATAL_EXIT_CODE);
288
289   insns = new hash_table <insn_hasher> (31);
290   stubs = new hash_table <nofree_string_hash> (31);
291   have_funcs = new hash_map <nofree_string_hash, const char *>;
292
293   md_rtx_info info;
294   while (read_md_rtx (&info))
295     switch (GET_CODE (info.def))
296       {
297       case DEFINE_INSN:
298       case DEFINE_EXPAND:
299         add_insn (&info);
300         break;
301
302       default:
303         break;
304       }
305
306   printf ("/* Generated automatically by the program `gentarget-def'.  */\n");
307   printf ("#ifndef GCC_INSN_TARGET_DEF_H\n");
308   printf ("#define GCC_INSN_TARGET_DEF_H\n");
309
310   /* Output a routine to convert an rtx to an rtx_insn sequence.
311      ??? At some point the gen_* functions themselves should return
312          rtx_insns.  */
313   printf ("\nstatic inline rtx_insn *\n");
314   printf ("insnify (rtx x)\n");
315   printf ("{\n");
316   printf ("  if (!x)\n");
317   printf ("    return NULL;\n");
318   printf ("  if (rtx_insn *insn = dyn_cast <rtx_insn *> (x))\n");
319   printf ("    return insn;\n");
320   printf ("  start_sequence ();\n");
321   printf ("  emit (x, false);\n");
322   printf ("  rtx_insn *res = get_insns ();\n");
323   printf ("  end_sequence ();\n");
324   printf ("  return res;\n");
325   printf ("}\n");
326
327 #define DEF_TARGET_INSN(INSN, ARGS) \
328   def_target_insn (#INSN, #ARGS);
329 #include "target-insns.def"
330 #undef DEF_TARGET_INSN
331
332   printf ("\n#endif /* GCC_INSN_TARGET_DEF_H */\n");
333
334   if (have_error || ferror (stdout) || fflush (stdout) || fclose (stdout))
335     return FATAL_EXIT_CODE;
336
337   return SUCCESS_EXIT_CODE;
338 }