1/* Generate code from machine description to perform peephole optimizations. 2 Copyright (C) 1987-2020 Free Software Foundation, Inc. 3 4This file is part of GCC. 5 6GCC is free software; you can redistribute it and/or modify it under 7the terms of the GNU General Public License as published by the Free 8Software Foundation; either version 3, or (at your option) any later 9version. 10 11GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12WARRANTY; without even the implied warranty of MERCHANTABILITY or 13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14for more details. 15 16You should have received a copy of the GNU General Public License 17along 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 36struct link 37{ 38 struct link *next; 39 int pos; 40 int vecelt; 41}; 42 43static int max_opno; 44 45/* Number of operands used in current peephole definition. */ 46 47static int n_operands; 48 49static void match_rtx (rtx, struct link *, int); 50static void print_path (struct link *); 51static void print_code (RTX_CODE); 52 53static void 54gen_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 (" insn = ins1;\n"); 63 64 for (i = 0; i < ninsns; i++) 65 { 66 if (i > 0) 67 { 68 printf (" do { insn = NEXT_INSN (insn);\n"); 69 printf (" if (insn == 0) goto L%d; }\n", info->index); 70 printf (" while (NOTE_P (insn)\n"); 71 printf ("\t || (NONJUMP_INSN_P (insn)\n"); 72 printf ("\t && (GET_CODE (PATTERN (insn)) == USE\n"); 73 printf ("\t\t || GET_CODE (PATTERN (insn)) == CLOBBER)));\n"); 74 75 printf (" if (LABEL_P (insn)\n\ 76 || BARRIER_P (insn))\n goto L%d;\n", info->index); 77 } 78 79 printf (" 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 (" 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 (" 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 (" INSN_CODE (ins1) = %d;\n", info->index); 105 106 /* Delete the remaining insns. */ 107 if (ninsns > 1) 108 printf (" delete_for_peephole (NEXT_INSN (ins1), insn);\n"); 109 110 /* See reload1.c for insertion of NOTE which guarantees that this 111 cannot be zero. */ 112 printf (" return NEXT_INSN (insn);\n"); 113 114 printf (" L%d:\n\n", info->index); 115} 116 117static void 118match_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 (" x = "); 141 print_path (path); 142 printf (";\n"); 143 144 printf (" operands[%d] = x;\n", XINT (x, 0)); 145 if (XSTR (x, 1) && XSTR (x, 1)[0]) 146 printf (" 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 (" x = "); 153 print_path (path); 154 printf (";\n"); 155 156 printf (" 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 (" x = "); 162 print_path (path); 163 printf (";\n"); 164 165 printf (" if (GET_CODE (operands[%d]) != GET_CODE (x)\n", XINT (x, 0)); 166 printf (" || GET_MODE (operands[%d]) != GET_MODE (x)) goto L%d;\n", 167 XINT (x, 0), fail_label); 168 printf (" 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), &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 (" x = "); 185 print_path (path); 186 printf (";\n"); 187 188 printf (" operands[%d] = x;\n", XINT (x, 0)); 189 if (XSTR (x, 1) && XSTR (x, 1)[0]) 190 printf (" 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), &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 (" x = "); 208 print_path (path); 209 printf (";\n"); 210 211 printf (" if (GET_CODE (x) != PARALLEL) goto L%d;\n", fail_label); 212 printf (" operands[%d] = x;\n", XINT (x, 0)); 213 if (XSTR (x, 1) && XSTR (x, 1)[0]) 214 printf (" 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), &link, fail_label); 222 } 223 return; 224 225 default: 226 break; 227 } 228 229 printf (" x = "); 230 print_path (path); 231 printf (";\n"); 232 233 printf (" if (GET_CODE (x) != "); 234 print_code (code); 235 printf (") goto L%d;\n", fail_label); 236 237 if (GET_MODE (x) != VOIDmode) 238 { 239 printf (" 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), &link, fail_label); 252 else if (fmt[i] == 'E') 253 { 254 int j; 255 printf (" 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), &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 (" x = "); 269 print_path (path); 270 printf (";\n"); 271 } 272 273 printf (" 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 (" 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 (" x = "); 288 print_path (path); 289 printf (";\n"); 290 } 291 292 printf (" if (XWINT (x, %d) != ", i); 293 printf (HOST_WIDE_INT_PRINT_DEC, XWINT (x, i)); 294 printf (") 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 (" x = "); 302 print_path (path); 303 printf (";\n"); 304 } 305 306 printf (" 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 319static void 320print_path (struct link *path) 321{ 322 if (path == 0) 323 printf ("pat"); 324 else if (path->vecelt >= 0) 325 { 326 printf ("XVECEXP ("); 327 print_path (path->next); 328 printf (", %d, %d)", path->pos, path->vecelt); 329 } 330 else 331 { 332 printf ("XEXP ("); 333 print_path (path->next); 334 printf (", %d)", path->pos); 335 } 336} 337 338static void 339print_code (RTX_CODE code) 340{ 341 const char *p1; 342 for (p1 = GET_RTX_NAME (code); *p1; p1++) 343 putchar (TOUPPER (*p1)); 344} 345 346extern int main (int, const char **); 347 348int 349main (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 ("/* Generated automatically by the program `genpeep'\n\ 359from the machine description file `md'. */\n\n"); 360 361 printf ("#define IN_TARGET_CODE 1\n"); 362 printf ("#include \"config.h\"\n"); 363 printf ("#include \"system.h\"\n"); 364 printf ("#include \"coretypes.h\"\n"); 365 printf ("#include \"backend.h\"\n"); 366 printf ("#include \"tree.h\"\n"); 367 printf ("#include \"rtl.h\"\n"); 368 printf ("#include \"insn-config.h\"\n"); 369 printf ("#include \"alias.h\"\n"); 370 printf ("#include \"varasm.h\"\n"); 371 printf ("#include \"stor-layout.h\"\n"); 372 printf ("#include \"calls.h\"\n"); 373 printf ("#include \"memmodel.h\"\n"); 374 printf ("#include \"tm_p.h\"\n"); 375 printf ("#include \"regs.h\"\n"); 376 printf ("#include \"output.h\"\n"); 377 printf ("#include \"recog.h\"\n"); 378 printf ("#include \"except.h\"\n"); 379 printf ("#include \"diagnostic-core.h\"\n"); 380 printf ("#include \"flags.h\"\n"); 381 printf ("#include \"tm-constrs.h\"\n\n"); 382 383 printf ("extern rtx peep_operand[];\n\n"); 384 printf ("#define operands peep_operand\n\n"); 385 386 printf ("rtx_insn *\npeephole (rtx_insn *ins1)\n{\n"); 387 printf (" rtx_insn *insn ATTRIBUTE_UNUSED;\n"); 388 printf (" rtx x ATTRIBUTE_UNUSED, pat ATTRIBUTE_UNUSED;\n\n"); 389 390 /* Early out: no peepholes for insns followed by barriers. */ 391 printf (" if (NEXT_INSN (ins1)\n"); 392 printf (" && BARRIER_P (NEXT_INSN (ins1)))\n"); 393 printf (" 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); 403 break; 404 405 default: 406 break; 407 } 408 409 printf (" return 0;\n}\n\n"); 410 411 if (max_opno == -1) 412 max_opno = 1; 413 414 printf ("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