1 /* Generate code to initialize optabs from machine description. 2 Copyright (C) 1993-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 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 #define DEF_RTL_EXPR(V, N, X, C) #V, 31 32 static const char * const rtx_upname[] = { 33 #include "rtl.def" 34 }; 35 36 #undef DEF_RTL_EXPR 37 38 /* Vector in which to collect insns that match. */ 39 static vec<optab_pattern> patterns; 40 41 static void 42 gen_insn (md_rtx_info *info) 43 { 44 optab_pattern p; 45 if (find_optab (&p, XSTR (info->def, 0))) 46 patterns.safe_push (p); 47 } 48 49 static int 50 pattern_cmp (const void *va, const void *vb) 51 { 52 const optab_pattern *a = (const optab_pattern *)va; 53 const optab_pattern *b = (const optab_pattern *)vb; 54 return a->sort_num - b->sort_num; 55 } 56 57 static int 58 optab_kind_cmp (const void *va, const void *vb) 59 { 60 const optab_def *a = (const optab_def *)va; 61 const optab_def *b = (const optab_def *)vb; 62 int diff = a->kind - b->kind; 63 if (diff == 0) 64 diff = a->op - b->op; 65 return diff; 66 } 67 68 static int 69 optab_rcode_cmp (const void *va, const void *vb) 70 { 71 const optab_def *a = (const optab_def *)va; 72 const optab_def *b = (const optab_def *)vb; 73 return a->rcode - b->rcode; 74 } 75 76 static const char *header_file_name = "init-opinit.h"; 77 static const char *source_file_name = "init-opinit.c"; 78 79 static bool 80 handle_arg (const char *arg) 81 { 82 switch (arg[1]) 83 { 84 case 'h': 85 header_file_name = &arg[2]; 86 return true; 87 case 'c': 88 source_file_name = &arg[2]; 89 return true; 90 default: 91 return false; 92 } 93 } 94 95 static FILE * 96 open_outfile (const char *file_name) 97 { 98 FILE *f = fopen (file_name, "w"); 99 if (!f) 100 fatal ("cannot open file %s: %s", file_name, xstrerror (errno)); 101 fprintf (f, 102 "/* Generated automatically by the program `genopinit'\n" 103 " from the machine description file `md'. */\n\n"); 104 return f; 105 } 106 107 int 108 main (int argc, const char **argv) 109 { 110 FILE *h_file, *s_file; 111 unsigned int i, j, n, last_kind[5]; 112 optab_pattern *p; 113 114 progname = "genopinit"; 115 116 if (NUM_OPTABS > 0xffff || MAX_MACHINE_MODE >= 0xff) 117 fatal ("genopinit range assumptions invalid"); 118 119 if (!init_rtx_reader_args_cb (argc, argv, handle_arg)) 120 return (FATAL_EXIT_CODE); 121 122 h_file = open_outfile (header_file_name); 123 s_file = open_outfile (source_file_name); 124 125 /* Read the machine description. */ 126 md_rtx_info info; 127 while (read_md_rtx (&info)) 128 switch (GET_CODE (info.def)) 129 { 130 case DEFINE_INSN: 131 case DEFINE_EXPAND: 132 gen_insn (&info); 133 break; 134 135 default: 136 break; 137 } 138 139 /* Sort the collected patterns. */ 140 patterns.qsort (pattern_cmp); 141 142 /* Now that we've handled the "extra" patterns, eliminate them from 143 the optabs array. That way they don't get in the way below. */ 144 n = num_optabs; 145 for (i = 0; i < n; ) 146 if (optabs[i].base == NULL) 147 optabs[i] = optabs[--n]; 148 else 149 ++i; 150 151 /* Sort the (real) optabs. Better than forcing the optabs.def file to 152 remain sorted by kind. We also scrogged any real ordering with the 153 purging of the X patterns above. */ 154 qsort (optabs, n, sizeof (optab_def), optab_kind_cmp); 155 156 fprintf (h_file, "#ifndef GCC_INSN_OPINIT_H\n"); 157 fprintf (h_file, "#define GCC_INSN_OPINIT_H 1\n"); 158 159 /* Emit the optab enumeration for the header file. */ 160 fprintf (h_file, "enum optab_tag {\n"); 161 for (i = j = 0; i < n; ++i) 162 { 163 optabs[i].op = i; 164 fprintf (h_file, " %s,\n", optabs[i].name); 165 if (optabs[i].kind != j) 166 last_kind[j++] = i - 1; 167 } 168 fprintf (h_file, " FIRST_CONV_OPTAB = %s,\n", optabs[last_kind[0]+1].name); 169 fprintf (h_file, " LAST_CONVLIB_OPTAB = %s,\n", optabs[last_kind[1]].name); 170 fprintf (h_file, " LAST_CONV_OPTAB = %s,\n", optabs[last_kind[2]].name); 171 fprintf (h_file, " FIRST_NORM_OPTAB = %s,\n", optabs[last_kind[2]+1].name); 172 fprintf (h_file, " LAST_NORMLIB_OPTAB = %s,\n", optabs[last_kind[3]].name); 173 fprintf (h_file, " LAST_NORM_OPTAB = %s\n", optabs[i-1].name); 174 fprintf (h_file, "};\n\n"); 175 176 fprintf (h_file, "#define NUM_OPTABS %u\n", n); 177 fprintf (h_file, "#define NUM_CONVLIB_OPTABS %u\n", 178 last_kind[1] - last_kind[0]); 179 fprintf (h_file, "#define NUM_NORMLIB_OPTABS %u\n", 180 last_kind[3] - last_kind[2]); 181 fprintf (h_file, "#define NUM_OPTAB_PATTERNS %u\n", 182 (unsigned) patterns.length ()); 183 184 fprintf (h_file, 185 "typedef enum optab_tag optab;\n" 186 "typedef enum optab_tag convert_optab;\n" 187 "typedef enum optab_tag direct_optab;\n" 188 "\n" 189 "struct optab_libcall_d\n" 190 "{\n" 191 " char libcall_suffix;\n" 192 " const char *libcall_basename;\n" 193 " void (*libcall_gen) (optab, const char *name,\n" 194 " char suffix, machine_mode);\n" 195 "};\n" 196 "\n" 197 "struct convert_optab_libcall_d\n" 198 "{\n" 199 " const char *libcall_basename;\n" 200 " void (*libcall_gen) (convert_optab, const char *name,\n" 201 " machine_mode, machine_mode);\n" 202 "};\n" 203 "\n" 204 "/* Given an enum insn_code, access the function to construct\n" 205 " the body of that kind of insn. */\n" 206 "#define GEN_FCN(CODE) (insn_data[CODE].genfun)\n" 207 "\n" 208 "#ifdef NUM_RTX_CODE\n" 209 "/* Contains the optab used for each rtx code, and vice-versa. */\n" 210 "extern const optab code_to_optab_[NUM_RTX_CODE];\n" 211 "extern const enum rtx_code optab_to_code_[NUM_OPTABS];\n" 212 "\n" 213 "static inline optab\n" 214 "code_to_optab (enum rtx_code code)\n" 215 "{\n" 216 " return code_to_optab_[code];\n" 217 "}\n" 218 "\n" 219 "static inline enum rtx_code\n" 220 "optab_to_code (optab op)\n" 221 "{\n" 222 " return optab_to_code_[op];\n" 223 "}\n" 224 "#endif\n" 225 "\n" 226 "extern const struct convert_optab_libcall_d convlib_def[NUM_CONVLIB_OPTABS];\n" 227 "extern const struct optab_libcall_d normlib_def[NUM_NORMLIB_OPTABS];\n" 228 "\n" 229 "/* Returns the active icode for the given (encoded) optab. */\n" 230 "extern enum insn_code raw_optab_handler (unsigned);\n" 231 "extern bool swap_optab_enable (optab, machine_mode, bool);\n" 232 "\n" 233 "/* Target-dependent globals. */\n" 234 "struct target_optabs {\n" 235 " /* Patterns that are used by optabs that are enabled for this target. */\n" 236 " bool pat_enable[NUM_OPTAB_PATTERNS];\n" 237 "\n" 238 " /* Cache if the target supports vec_gather_load for at least one vector\n" 239 " mode. */\n" 240 " bool supports_vec_gather_load;\n" 241 " bool supports_vec_gather_load_cached;\n" 242 " bool supports_vec_scatter_store;\n" 243 " bool supports_vec_scatter_store_cached;\n" 244 "};\n" 245 "extern void init_all_optabs (struct target_optabs *);\n" 246 "\n" 247 "extern struct target_optabs default_target_optabs;\n" 248 "extern struct target_optabs *this_fn_optabs;\n" 249 "#if SWITCHABLE_TARGET\n" 250 "extern struct target_optabs *this_target_optabs;\n" 251 "#else\n" 252 "#define this_target_optabs (&default_target_optabs)\n" 253 "#endif\n"); 254 255 fprintf (s_file, 256 "#define IN_TARGET_CODE 1\n" 257 "#include \"config.h\"\n" 258 "#include \"system.h\"\n" 259 "#include \"coretypes.h\"\n" 260 "#include \"backend.h\"\n" 261 "#include \"predict.h\"\n" 262 "#include \"tree.h\"\n" 263 "#include \"rtl.h\"\n" 264 "#include \"alias.h\"\n" 265 "#include \"varasm.h\"\n" 266 "#include \"stor-layout.h\"\n" 267 "#include \"calls.h\"\n" 268 "#include \"memmodel.h\"\n" 269 "#include \"tm_p.h\"\n" 270 "#include \"flags.h\"\n" 271 "#include \"insn-config.h\"\n" 272 "#include \"expmed.h\"\n" 273 "#include \"dojump.h\"\n" 274 "#include \"explow.h\"\n" 275 "#include \"emit-rtl.h\"\n" 276 "#include \"stmt.h\"\n" 277 "#include \"expr.h\"\n" 278 "#include \"insn-codes.h\"\n" 279 "#include \"optabs.h\"\n" 280 "\n" 281 "struct optab_pat {\n" 282 " unsigned scode;\n" 283 " enum insn_code icode;\n" 284 "};\n\n"); 285 286 fprintf (s_file, 287 "static const struct optab_pat pats[NUM_OPTAB_PATTERNS] = {\n"); 288 for (i = 0; patterns.iterate (i, &p); ++i) 289 fprintf (s_file, " { %#08x, CODE_FOR_%s },\n", p->sort_num, p->name); 290 fprintf (s_file, "};\n\n"); 291 292 fprintf (s_file, "void\ninit_all_optabs (struct target_optabs *optabs)\n{\n"); 293 fprintf (s_file, " bool *ena = optabs->pat_enable;\n"); 294 for (i = 0; patterns.iterate (i, &p); ++i) 295 fprintf (s_file, " ena[%u] = HAVE_%s;\n", i, p->name); 296 fprintf (s_file, "}\n\n"); 297 298 /* Perform a binary search on a pre-encoded optab+mode*2. */ 299 /* ??? Perhaps even better to generate a minimal perfect hash. 300 Using gperf directly is awkward since it's so geared to working 301 with strings. Plus we have no visibility into the ordering of 302 the hash entries, which complicates the pat_enable array. */ 303 fprintf (s_file, 304 "static int\n" 305 "lookup_handler (unsigned scode)\n" 306 "{\n" 307 " int l = 0, h = ARRAY_SIZE (pats), m;\n" 308 " while (h > l)\n" 309 " {\n" 310 " m = (h + l) / 2;\n" 311 " if (scode == pats[m].scode)\n" 312 " return m;\n" 313 " else if (scode < pats[m].scode)\n" 314 " h = m;\n" 315 " else\n" 316 " l = m + 1;\n" 317 " }\n" 318 " return -1;\n" 319 "}\n\n"); 320 321 fprintf (s_file, 322 "enum insn_code\n" 323 "raw_optab_handler (unsigned scode)\n" 324 "{\n" 325 " int i = lookup_handler (scode);\n" 326 " return (i >= 0 && this_fn_optabs->pat_enable[i]\n" 327 " ? pats[i].icode : CODE_FOR_nothing);\n" 328 "}\n\n"); 329 330 fprintf (s_file, 331 "bool\n" 332 "swap_optab_enable (optab op, machine_mode m, bool set)\n" 333 "{\n" 334 " unsigned scode = (op << 16) | m;\n" 335 " int i = lookup_handler (scode);\n" 336 " if (i >= 0)\n" 337 " {\n" 338 " bool ret = this_fn_optabs->pat_enable[i];\n" 339 " this_fn_optabs->pat_enable[i] = set;\n" 340 " return ret;\n" 341 " }\n" 342 " else\n" 343 " {\n" 344 " gcc_assert (!set);\n" 345 " return false;\n" 346 " }\n" 347 "}\n\n"); 348 349 /* C++ (even G++) does not support (non-trivial) designated initializers. 350 To work around that, generate these arrays programatically rather than 351 by our traditional multiple inclusion of def files. */ 352 353 fprintf (s_file, 354 "const struct convert_optab_libcall_d " 355 "convlib_def[NUM_CONVLIB_OPTABS] = {\n"); 356 for (i = last_kind[0] + 1; i <= last_kind[1]; ++i) 357 fprintf (s_file, " { %s, %s },\n", optabs[i].base, optabs[i].libcall); 358 fprintf (s_file, "};\n\n"); 359 360 fprintf (s_file, 361 "const struct optab_libcall_d " 362 "normlib_def[NUM_NORMLIB_OPTABS] = {\n"); 363 for (i = last_kind[2] + 1; i <= last_kind[3]; ++i) 364 fprintf (s_file, " { %s, %s, %s },\n", 365 optabs[i].suffix, optabs[i].base, optabs[i].libcall); 366 fprintf (s_file, "};\n\n"); 367 368 fprintf (s_file, "enum rtx_code const optab_to_code_[NUM_OPTABS] = {\n"); 369 for (i = 0; i < n; ++i) 370 fprintf (s_file, " %s,\n", rtx_upname[optabs[i].fcode]); 371 fprintf (s_file, "};\n\n"); 372 373 qsort (optabs, n, sizeof (optab_def), optab_rcode_cmp); 374 375 fprintf (s_file, "const optab code_to_optab_[NUM_RTX_CODE] = {\n"); 376 for (j = 0; optabs[j].rcode == UNKNOWN; ++j) 377 continue; 378 for (i = 0; i < NON_GENERATOR_NUM_RTX_CODE; ++i) 379 { 380 if (j < n && optabs[j].rcode == i) 381 fprintf (s_file, " %s,\n", optabs[j++].name); 382 else 383 fprintf (s_file, " unknown_optab,\n"); 384 } 385 fprintf (s_file, "};\n\n"); 386 387 fprintf (h_file, "#endif\n"); 388 return (fclose (h_file) == 0 && fclose (s_file) == 0 389 ? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE); 390 } 391