1 /* Generate code from machine description to perform peephole optimizations. 2 Copyright (C) 1987-2022 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 /* 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 36 struct link 37 { 38 struct link *next; 39 int pos; 40 int vecelt; 41 }; 42 43 static int max_opno; 44 45 /* Number of operands used in current peephole definition. */ 46 47 static int n_operands; 48 49 static void match_rtx (rtx, struct link *, int); 50 static void print_path (struct link *); 51 static void print_code (RTX_CODE); 52 53 static void 55 gen_peephole (md_rtx_info *info) 56 { 57 rtx peep = info->def; 58 int ninsns = XVECLEN (peep, 0); 59 int i; 60 61 n_operands = 0; 62 63 printf (" insn = ins1;\n"); 64 65 for (i = 0; i < ninsns; i++) 66 { 67 if (i > 0) 68 { 69 printf (" do { insn = NEXT_INSN (insn);\n"); 70 printf (" if (insn == 0) goto L%d; }\n", info->index); 71 printf (" while (NOTE_P (insn)\n"); 72 printf ("\t || (NONJUMP_INSN_P (insn)\n"); 73 printf ("\t && (GET_CODE (PATTERN (insn)) == USE\n"); 74 printf ("\t\t || GET_CODE (PATTERN (insn)) == CLOBBER)));\n"); 75 76 printf (" if (LABEL_P (insn)\n\ 77 || BARRIER_P (insn))\n goto L%d;\n", info->index); 78 } 79 80 printf (" pat = PATTERN (insn);\n"); 81 82 /* Walk the insn's pattern, remembering at all times the path 83 down to the walking point. */ 84 85 match_rtx (XVECEXP (peep, 0, i), NULL, info->index); 86 } 87 88 /* We get this far if the pattern matches. 89 Now test the extra condition. */ 90 91 if (XSTR (peep, 1) && XSTR (peep, 1)[0]) 92 printf (" if (! (%s)) goto L%d;\n", 93 XSTR (peep, 1), info->index); 94 95 /* If that matches, construct new pattern and put it in the first insn. 96 This new pattern will never be matched. 97 It exists only so that insn-extract can get the operands back. 98 So use a simple regular form: a PARALLEL containing a vector 99 of all the operands. */ 100 101 printf (" PATTERN (ins1) = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (%d, operands));\n", n_operands); 102 103 /* Record this define_peephole's insn code in the insn, 104 as if it had been recognized to match this. */ 105 printf (" INSN_CODE (ins1) = %d;\n", info->index); 106 107 /* Delete the remaining insns. */ 108 if (ninsns > 1) 109 printf (" delete_for_peephole (NEXT_INSN (ins1), insn);\n"); 110 111 /* See reload1.cc for insertion of NOTE which guarantees that this 112 cannot be zero. */ 113 printf (" return NEXT_INSN (insn);\n"); 114 115 printf (" L%d:\n\n", info->index); 116 } 117 118 static void 120 match_rtx (rtx x, struct link *path, int fail_label) 121 { 122 RTX_CODE code; 123 int i; 124 int len; 125 const char *fmt; 126 struct link link; 127 128 if (x == 0) 129 return; 130 131 132 code = GET_CODE (x); 133 134 switch (code) 135 { 136 case MATCH_OPERAND: 137 if (XINT (x, 0) > max_opno) 138 max_opno = XINT (x, 0); 139 if (XINT (x, 0) >= n_operands) 140 n_operands = 1 + XINT (x, 0); 141 142 printf (" x = "); 143 print_path (path); 144 printf (";\n"); 145 146 printf (" operands[%d] = x;\n", XINT (x, 0)); 147 if (XSTR (x, 1) && XSTR (x, 1)[0]) 148 printf (" if (! %s (x, %smode)) goto L%d;\n", 149 XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label); 150 return; 151 152 case MATCH_DUP: 153 case MATCH_PAR_DUP: 154 printf (" x = "); 155 print_path (path); 156 printf (";\n"); 157 158 printf (" if (!rtx_equal_p (operands[%d], x)) goto L%d;\n", 159 XINT (x, 0), fail_label); 160 return; 161 162 case MATCH_OP_DUP: 163 printf (" x = "); 164 print_path (path); 165 printf (";\n"); 166 167 printf (" if (GET_CODE (operands[%d]) != GET_CODE (x)\n", XINT (x, 0)); 168 printf (" || GET_MODE (operands[%d]) != GET_MODE (x)) goto L%d;\n", 169 XINT (x, 0), fail_label); 170 printf (" operands[%d] = x;\n", XINT (x, 0)); 171 link.next = path; 172 link.vecelt = -1; 173 for (i = 0; i < XVECLEN (x, 1); i++) 174 { 175 link.pos = i; 176 match_rtx (XVECEXP (x, 1, i), &link, fail_label); 177 } 178 return; 179 180 case MATCH_OPERATOR: 181 if (XINT (x, 0) > max_opno) 182 max_opno = XINT (x, 0); 183 if (XINT (x, 0) >= n_operands) 184 n_operands = 1 + XINT (x, 0); 185 186 printf (" x = "); 187 print_path (path); 188 printf (";\n"); 189 190 printf (" operands[%d] = x;\n", XINT (x, 0)); 191 if (XSTR (x, 1) && XSTR (x, 1)[0]) 192 printf (" if (! %s (x, %smode)) goto L%d;\n", 193 XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label); 194 link.next = path; 195 link.vecelt = -1; 196 for (i = 0; i < XVECLEN (x, 2); i++) 197 { 198 link.pos = i; 199 match_rtx (XVECEXP (x, 2, i), &link, fail_label); 200 } 201 return; 202 203 case MATCH_PARALLEL: 204 if (XINT (x, 0) > max_opno) 205 max_opno = XINT (x, 0); 206 if (XINT (x, 0) >= n_operands) 207 n_operands = 1 + XINT (x, 0); 208 209 printf (" x = "); 210 print_path (path); 211 printf (";\n"); 212 213 printf (" if (GET_CODE (x) != PARALLEL) goto L%d;\n", fail_label); 214 printf (" operands[%d] = x;\n", XINT (x, 0)); 215 if (XSTR (x, 1) && XSTR (x, 1)[0]) 216 printf (" if (! %s (x, %smode)) goto L%d;\n", 217 XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label); 218 link.next = path; 219 link.pos = 0; 220 for (i = 0; i < XVECLEN (x, 2); i++) 221 { 222 link.vecelt = i; 223 match_rtx (XVECEXP (x, 2, i), &link, fail_label); 224 } 225 return; 226 227 default: 228 break; 229 } 230 231 printf (" x = "); 232 print_path (path); 233 printf (";\n"); 234 235 printf (" if (GET_CODE (x) != "); 236 print_code (code); 237 printf (") goto L%d;\n", fail_label); 238 239 if (GET_MODE (x) != VOIDmode) 240 { 241 printf (" if (GET_MODE (x) != %smode) goto L%d;\n", 242 GET_MODE_NAME (GET_MODE (x)), fail_label); 243 } 244 245 link.next = path; 246 link.vecelt = -1; 247 fmt = GET_RTX_FORMAT (code); 248 len = GET_RTX_LENGTH (code); 249 for (i = 0; i < len; i++) 250 { 251 link.pos = i; 252 if (fmt[i] == 'e' || fmt[i] == 'u') 253 match_rtx (XEXP (x, i), &link, fail_label); 254 else if (fmt[i] == 'E') 255 { 256 int j; 257 printf (" if (XVECLEN (x, %d) != %d) goto L%d;\n", 258 i, XVECLEN (x, i), fail_label); 259 for (j = 0; j < XVECLEN (x, i); j++) 260 { 261 link.vecelt = j; 262 match_rtx (XVECEXP (x, i, j), &link, fail_label); 263 } 264 } 265 else if (fmt[i] == 'i') 266 { 267 /* Make sure that at run time `x' is the RTX we want to test. */ 268 if (i != 0) 269 { 270 printf (" x = "); 271 print_path (path); 272 printf (";\n"); 273 } 274 275 printf (" if (XINT (x, %d) != %d) goto L%d;\n", 276 i, XINT (x, i), fail_label); 277 } 278 else if (fmt[i] == 'r') 279 { 280 gcc_assert (i == 0); 281 printf (" if (REGNO (x) != %d) goto L%d;\n", 282 REGNO (x), fail_label); 283 } 284 else if (fmt[i] == 'w') 285 { 286 /* Make sure that at run time `x' is the RTX we want to test. */ 287 if (i != 0) 288 { 289 printf (" x = "); 290 print_path (path); 291 printf (";\n"); 292 } 293 294 printf (" if (XWINT (x, %d) != ", i); 295 printf (HOST_WIDE_INT_PRINT_DEC, XWINT (x, i)); 296 printf (") goto L%d;\n", fail_label); 297 } 298 else if (fmt[i] == 's') 299 { 300 /* Make sure that at run time `x' is the RTX we want to test. */ 301 if (i != 0) 302 { 303 printf (" x = "); 304 print_path (path); 305 printf (";\n"); 306 } 307 308 printf (" if (strcmp (XSTR (x, %d), \"%s\")) goto L%d;\n", 309 i, XSTR (x, i), fail_label); 310 } 311 else if (fmt[i] == 'p') 312 /* Not going to support subregs for legacy define_peeholes. */ 313 gcc_unreachable (); 314 } 315 } 316 317 /* Given a PATH, representing a path down the instruction's 318 pattern from the root to a certain point, output code to 319 evaluate to the rtx at that point. */ 320 321 static void 322 print_path (struct link *path) 323 { 324 if (path == 0) 325 printf ("pat"); 326 else if (path->vecelt >= 0) 327 { 328 printf ("XVECEXP ("); 329 print_path (path->next); 330 printf (", %d, %d)", path->pos, path->vecelt); 331 } 332 else 333 { 334 printf ("XEXP ("); 335 print_path (path->next); 336 printf (", %d)", path->pos); 337 } 338 } 339 340 static void 342 print_code (RTX_CODE code) 343 { 344 const char *p1; 345 for (p1 = GET_RTX_NAME (code); *p1; p1++) 346 putchar (TOUPPER (*p1)); 347 } 348 349 extern int main (int, const char **); 350 351 int 352 main (int argc, const char **argv) 353 { 354 max_opno = -1; 355 356 progname = "genpeep"; 357 358 if (!init_rtx_reader_args (argc, argv)) 359 return (FATAL_EXIT_CODE); 360 361 printf ("/* Generated automatically by the program `genpeep'\n\ 362 from the machine description file `md'. */\n\n"); 363 364 printf ("#define IN_TARGET_CODE 1\n"); 365 printf ("#include \"config.h\"\n"); 366 printf ("#include \"system.h\"\n"); 367 printf ("#include \"coretypes.h\"\n"); 368 printf ("#include \"backend.h\"\n"); 369 printf ("#include \"tree.h\"\n"); 370 printf ("#include \"rtl.h\"\n"); 371 printf ("#include \"insn-config.h\"\n"); 372 printf ("#include \"alias.h\"\n"); 373 printf ("#include \"varasm.h\"\n"); 374 printf ("#include \"stor-layout.h\"\n"); 375 printf ("#include \"calls.h\"\n"); 376 printf ("#include \"memmodel.h\"\n"); 377 printf ("#include \"tm_p.h\"\n"); 378 printf ("#include \"regs.h\"\n"); 379 printf ("#include \"output.h\"\n"); 380 printf ("#include \"recog.h\"\n"); 381 printf ("#include \"except.h\"\n"); 382 printf ("#include \"diagnostic-core.h\"\n"); 383 printf ("#include \"flags.h\"\n"); 384 printf ("#include \"tm-constrs.h\"\n\n"); 385 386 printf ("extern rtx peep_operand[];\n\n"); 387 printf ("#define operands peep_operand\n\n"); 388 389 printf ("rtx_insn *\npeephole (rtx_insn *ins1)\n{\n"); 390 printf (" rtx_insn *insn ATTRIBUTE_UNUSED;\n"); 391 printf (" rtx x ATTRIBUTE_UNUSED, pat ATTRIBUTE_UNUSED;\n\n"); 392 393 /* Early out: no peepholes for insns followed by barriers. */ 394 printf (" if (NEXT_INSN (ins1)\n"); 395 printf (" && BARRIER_P (NEXT_INSN (ins1)))\n"); 396 printf (" return 0;\n\n"); 397 398 /* Read the machine description. */ 399 400 md_rtx_info info; 401 while (read_md_rtx (&info)) 402 switch (GET_CODE (info.def)) 403 { 404 case DEFINE_PEEPHOLE: 405 gen_peephole (&info); 406 break; 407 408 default: 409 break; 410 } 411 412 printf (" return 0;\n}\n\n"); 413 414 if (max_opno == -1) 415 max_opno = 1; 416 417 printf ("rtx peep_operand[%d];\n", max_opno + 1); 418 419 fflush (stdout); 420 return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); 421 } 422