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 } 339