Line data Source code
1 : /* Discovery of auto-inc and auto-dec instructions.
2 : Copyright (C) 2006-2026 Free Software Foundation, Inc.
3 : Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
4 :
5 : This file is part of GCC.
6 :
7 : GCC is free software; you can redistribute it and/or modify it under
8 : the terms of the GNU General Public License as published by the Free
9 : Software Foundation; either version 3, or (at your option) any later
10 : version.
11 :
12 : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with GCC; see the file COPYING3. If not see
19 : <http://www.gnu.org/licenses/>. */
20 :
21 : #include "config.h"
22 : #include "system.h"
23 : #include "coretypes.h"
24 : #include "backend.h"
25 : #include "target.h"
26 : #include "rtl.h"
27 : #include "tree.h"
28 : #include "predict.h"
29 : #include "df.h"
30 : #include "insn-config.h"
31 : #include "memmodel.h"
32 : #include "emit-rtl.h"
33 : #include "recog.h"
34 : #include "cfgrtl.h"
35 : #include "expr.h"
36 : #include "tree-pass.h"
37 : #include "dbgcnt.h"
38 : #include "print-rtl.h"
39 : #include "valtrack.h"
40 :
41 : /* This pass was originally removed from flow.c. However there is
42 : almost nothing that remains of that code.
43 :
44 : There are (4) basic forms that are matched:
45 :
46 : (1) FORM_PRE_ADD
47 : a <- b + c
48 : ...
49 : *a
50 :
51 : becomes
52 :
53 : a <- b
54 : ...
55 : *(a += c) pre
56 :
57 : or, alternately,
58 :
59 : a <- b + c
60 : ...
61 : *b
62 :
63 : becomes
64 :
65 : a <- b
66 : ...
67 : *(a += c) post
68 :
69 : This uses a post-add, but it's handled as FORM_PRE_ADD because
70 : the "increment" insn appears before the memory access.
71 :
72 :
73 : (2) FORM_PRE_INC
74 : a += c
75 : ...
76 : *a
77 :
78 : becomes
79 :
80 : ...
81 : *(a += c) pre
82 :
83 :
84 : (3) FORM_POST_ADD
85 : *a
86 : ...
87 : b <- a + c
88 :
89 : (For this case to be true, b must not be assigned or used between
90 : the *a and the assignment to b. B must also be a Pmode reg.)
91 :
92 : becomes
93 :
94 : b <- a
95 : *(b += c) post
96 : ...
97 :
98 :
99 : (4) FORM_POST_INC
100 : *a
101 : ...
102 : a <- a + c
103 :
104 : becomes
105 :
106 : *(a += c) post
107 : ...
108 :
109 :
110 : There are three types of values of c.
111 :
112 : 1) c is a constant equal to the width of the value being accessed by
113 : the pointer. This is useful for machines that have
114 : HAVE_PRE_INCREMENT, HAVE_POST_INCREMENT, HAVE_PRE_DECREMENT or
115 : HAVE_POST_DECREMENT defined.
116 :
117 : 2) c is a constant not equal to the width of the value being accessed
118 : by the pointer. This is useful for machines that have
119 : HAVE_PRE_MODIFY_DISP, HAVE_POST_MODIFY_DISP defined.
120 :
121 : 3) c is a register. This is useful for machines that have
122 : HAVE_PRE_MODIFY_REG, HAVE_POST_MODIFY_REG
123 :
124 : The is one special case: if a already had an offset equal to it +-
125 : its width and that offset is equal to -c when the increment was
126 : before the ref or +c if the increment was after the ref, then if we
127 : can do the combination but switch the pre/post bit. */
128 :
129 :
130 : enum form
131 : {
132 : FORM_PRE_ADD,
133 : FORM_PRE_INC,
134 : FORM_POST_ADD,
135 : FORM_POST_INC,
136 : FORM_last
137 : };
138 :
139 : /* The states of the second operands of mem refs and inc insns. If no
140 : second operand of the mem_ref was found, it is assumed to just be
141 : ZERO. SIZE is the size of the mode accessed in the memref. The
142 : ANY is used for constants that are not +-size or 0. REG is used if
143 : the forms are reg1 + reg2. */
144 :
145 : enum inc_state
146 : {
147 : INC_ZERO, /* == 0 */
148 : INC_NEG_SIZE, /* == +size */
149 : INC_POS_SIZE, /* == -size */
150 : INC_NEG_ANY, /* == some -constant */
151 : INC_POS_ANY, /* == some +constant */
152 : INC_REG, /* == some register */
153 : INC_last
154 : };
155 :
156 : /* The eight forms that pre/post inc/dec can take. */
157 : enum gen_form
158 : {
159 : NOTHING,
160 : SIMPLE_PRE_INC, /* ++size */
161 : SIMPLE_POST_INC, /* size++ */
162 : SIMPLE_PRE_DEC, /* --size */
163 : SIMPLE_POST_DEC, /* size-- */
164 : DISP_PRE, /* ++con */
165 : DISP_POST, /* con++ */
166 : REG_PRE, /* ++reg */
167 : REG_POST /* reg++ */
168 : };
169 :
170 : /* Tmp mem rtx for use in cost modeling. */
171 : static rtx mem_tmp;
172 :
173 : static enum inc_state
174 0 : set_inc_state (HOST_WIDE_INT val, poly_int64 size)
175 : {
176 0 : if (val == 0)
177 : return INC_ZERO;
178 0 : if (val < 0)
179 0 : return known_eq (val, -size) ? INC_NEG_SIZE : INC_NEG_ANY;
180 : else
181 0 : return known_eq (val, size) ? INC_POS_SIZE : INC_POS_ANY;
182 : }
183 :
184 : /* The DECISION_TABLE that describes what form, if any, the increment
185 : or decrement will take. It is a three dimensional table. The first
186 : index is the type of constant or register found as the second
187 : operand of the inc insn. The second index is the type of constant
188 : or register found as the second operand of the memory reference (if
189 : no second operand exists, 0 is used). The third index is the form
190 : and location (relative to the mem reference) of inc insn. */
191 :
192 : static bool initialized = false;
193 : static enum gen_form decision_table[INC_last][INC_last][FORM_last];
194 :
195 : static void
196 0 : init_decision_table (void)
197 : {
198 0 : enum gen_form value;
199 :
200 0 : if (HAVE_PRE_INCREMENT || HAVE_PRE_MODIFY_DISP)
201 : {
202 : /* Prefer the simple form if both are available. */
203 : value = (HAVE_PRE_INCREMENT) ? SIMPLE_PRE_INC : DISP_PRE;
204 :
205 : decision_table[INC_POS_SIZE][INC_ZERO][FORM_PRE_ADD] = value;
206 : decision_table[INC_POS_SIZE][INC_ZERO][FORM_PRE_INC] = value;
207 :
208 : decision_table[INC_POS_SIZE][INC_POS_SIZE][FORM_POST_ADD] = value;
209 : decision_table[INC_POS_SIZE][INC_POS_SIZE][FORM_POST_INC] = value;
210 : }
211 :
212 0 : if (HAVE_POST_INCREMENT || HAVE_POST_MODIFY_DISP)
213 : {
214 : /* Prefer the simple form if both are available. */
215 : value = (HAVE_POST_INCREMENT) ? SIMPLE_POST_INC : DISP_POST;
216 :
217 : decision_table[INC_POS_SIZE][INC_ZERO][FORM_POST_ADD] = value;
218 : decision_table[INC_POS_SIZE][INC_ZERO][FORM_POST_INC] = value;
219 :
220 : decision_table[INC_POS_SIZE][INC_NEG_SIZE][FORM_PRE_ADD] = value;
221 : decision_table[INC_POS_SIZE][INC_NEG_SIZE][FORM_PRE_INC] = value;
222 : }
223 :
224 0 : if (HAVE_PRE_DECREMENT || HAVE_PRE_MODIFY_DISP)
225 : {
226 : /* Prefer the simple form if both are available. */
227 : value = (HAVE_PRE_DECREMENT) ? SIMPLE_PRE_DEC : DISP_PRE;
228 :
229 : decision_table[INC_NEG_SIZE][INC_ZERO][FORM_PRE_ADD] = value;
230 : decision_table[INC_NEG_SIZE][INC_ZERO][FORM_PRE_INC] = value;
231 :
232 : decision_table[INC_NEG_SIZE][INC_NEG_SIZE][FORM_POST_ADD] = value;
233 : decision_table[INC_NEG_SIZE][INC_NEG_SIZE][FORM_POST_INC] = value;
234 : }
235 :
236 0 : if (HAVE_POST_DECREMENT || HAVE_POST_MODIFY_DISP)
237 : {
238 : /* Prefer the simple form if both are available. */
239 : value = (HAVE_POST_DECREMENT) ? SIMPLE_POST_DEC : DISP_POST;
240 :
241 : decision_table[INC_NEG_SIZE][INC_ZERO][FORM_POST_ADD] = value;
242 : decision_table[INC_NEG_SIZE][INC_ZERO][FORM_POST_INC] = value;
243 :
244 : decision_table[INC_NEG_SIZE][INC_POS_SIZE][FORM_PRE_ADD] = value;
245 : decision_table[INC_NEG_SIZE][INC_POS_SIZE][FORM_PRE_INC] = value;
246 : }
247 :
248 0 : if (HAVE_PRE_MODIFY_DISP)
249 : {
250 : decision_table[INC_POS_ANY][INC_ZERO][FORM_PRE_ADD] = DISP_PRE;
251 : decision_table[INC_POS_ANY][INC_ZERO][FORM_PRE_INC] = DISP_PRE;
252 :
253 : decision_table[INC_POS_ANY][INC_POS_ANY][FORM_POST_ADD] = DISP_PRE;
254 : decision_table[INC_POS_ANY][INC_POS_ANY][FORM_POST_INC] = DISP_PRE;
255 :
256 : decision_table[INC_NEG_ANY][INC_ZERO][FORM_PRE_ADD] = DISP_PRE;
257 : decision_table[INC_NEG_ANY][INC_ZERO][FORM_PRE_INC] = DISP_PRE;
258 :
259 : decision_table[INC_NEG_ANY][INC_NEG_ANY][FORM_POST_ADD] = DISP_PRE;
260 : decision_table[INC_NEG_ANY][INC_NEG_ANY][FORM_POST_INC] = DISP_PRE;
261 : }
262 :
263 0 : if (HAVE_POST_MODIFY_DISP)
264 : {
265 : decision_table[INC_POS_ANY][INC_ZERO][FORM_POST_ADD] = DISP_POST;
266 : decision_table[INC_POS_ANY][INC_ZERO][FORM_POST_INC] = DISP_POST;
267 :
268 : decision_table[INC_POS_ANY][INC_NEG_ANY][FORM_PRE_ADD] = DISP_POST;
269 : decision_table[INC_POS_ANY][INC_NEG_ANY][FORM_PRE_INC] = DISP_POST;
270 :
271 : decision_table[INC_NEG_ANY][INC_ZERO][FORM_POST_ADD] = DISP_POST;
272 : decision_table[INC_NEG_ANY][INC_ZERO][FORM_POST_INC] = DISP_POST;
273 :
274 : decision_table[INC_NEG_ANY][INC_POS_ANY][FORM_PRE_ADD] = DISP_POST;
275 : decision_table[INC_NEG_ANY][INC_POS_ANY][FORM_PRE_INC] = DISP_POST;
276 : }
277 :
278 : /* This is much simpler than the other cases because we do not look
279 : for the reg1-reg2 case. Note that we do not have a INC_POS_REG
280 : and INC_NEG_REG states. Most of the use of such states would be
281 : on a target that had an R1 - R2 update address form.
282 :
283 : There is the remote possibility that you could also catch a = a +
284 : b; *(a - b) as a postdecrement of (a + b). However, it is
285 : unclear if *(a - b) would ever be generated on a machine that did
286 : not have that kind of addressing mode. The IA-64 and RS6000 will
287 : not do this, and I cannot speak for any other. If any
288 : architecture does have an a-b update for, these cases should be
289 : added. */
290 0 : if (HAVE_PRE_MODIFY_REG)
291 : {
292 : decision_table[INC_REG][INC_ZERO][FORM_PRE_ADD] = REG_PRE;
293 : decision_table[INC_REG][INC_ZERO][FORM_PRE_INC] = REG_PRE;
294 :
295 : decision_table[INC_REG][INC_REG][FORM_POST_ADD] = REG_PRE;
296 : decision_table[INC_REG][INC_REG][FORM_POST_INC] = REG_PRE;
297 : }
298 :
299 0 : if (HAVE_POST_MODIFY_REG)
300 : {
301 : decision_table[INC_REG][INC_ZERO][FORM_POST_ADD] = REG_POST;
302 : decision_table[INC_REG][INC_ZERO][FORM_POST_INC] = REG_POST;
303 : }
304 :
305 0 : initialized = true;
306 0 : }
307 :
308 : /* Parsed fields of an inc insn of the form "reg_res = reg0+reg1" or
309 : "reg_res = reg0+c". */
310 :
311 : static struct inc_insn
312 : {
313 : rtx_insn *insn; /* The insn being parsed. */
314 : rtx pat; /* The pattern of the insn. */
315 : bool reg1_is_const; /* True if reg1 is const, false if reg1 is a reg. */
316 : enum form form;
317 : rtx reg_res;
318 : rtx reg0;
319 : rtx reg1;
320 : enum inc_state reg1_state;/* The form of the const if reg1 is a const. */
321 : HOST_WIDE_INT reg1_val;/* Value if reg1 is const. */
322 : } inc_insn;
323 :
324 :
325 : /* Dump the parsed inc insn to FILE. */
326 :
327 : static void
328 0 : dump_inc_insn (FILE *file)
329 : {
330 0 : const char *f = ((inc_insn.form == FORM_PRE_ADD)
331 0 : || (inc_insn.form == FORM_PRE_INC)) ? "pre" : "post";
332 :
333 0 : dump_insn_slim (file, inc_insn.insn);
334 :
335 0 : switch (inc_insn.form)
336 : {
337 0 : case FORM_PRE_ADD:
338 0 : case FORM_POST_ADD:
339 0 : if (inc_insn.reg1_is_const)
340 0 : fprintf (file, "found %s add(%d) r[%d]=r[%d]+%d\n",
341 0 : f, INSN_UID (inc_insn.insn),
342 0 : REGNO (inc_insn.reg_res),
343 0 : REGNO (inc_insn.reg0), (int) inc_insn.reg1_val);
344 : else
345 0 : fprintf (file, "found %s add(%d) r[%d]=r[%d]+r[%d]\n",
346 0 : f, INSN_UID (inc_insn.insn),
347 0 : REGNO (inc_insn.reg_res),
348 0 : REGNO (inc_insn.reg0), REGNO (inc_insn.reg1));
349 : break;
350 :
351 0 : case FORM_PRE_INC:
352 0 : case FORM_POST_INC:
353 0 : if (inc_insn.reg1_is_const)
354 0 : fprintf (file, "found %s inc(%d) r[%d]+=%d\n",
355 0 : f, INSN_UID (inc_insn.insn),
356 0 : REGNO (inc_insn.reg_res), (int) inc_insn.reg1_val);
357 : else
358 0 : fprintf (file, "found %s inc(%d) r[%d]+=r[%d]\n",
359 0 : f, INSN_UID (inc_insn.insn),
360 0 : REGNO (inc_insn.reg_res), REGNO (inc_insn.reg1));
361 : break;
362 :
363 : default:
364 : break;
365 : }
366 0 : }
367 :
368 :
369 : /* Parsed fields of a mem ref of the form "*(reg0+reg1)" or "*(reg0+c)". */
370 :
371 : static struct mem_insn
372 : {
373 : rtx_insn *insn; /* The insn being parsed. */
374 : rtx pat; /* The pattern of the insn. */
375 : rtx *mem_loc; /* The address of the field that holds the mem */
376 : /* that is to be replaced. */
377 : bool reg1_is_const; /* True if reg1 is const, false if reg1 is a reg. */
378 : rtx reg0;
379 : rtx reg1; /* This is either a reg or a const depending on
380 : reg1_is_const. */
381 : enum inc_state reg1_state;/* The form of the const if reg1 is a const. */
382 : HOST_WIDE_INT reg1_val;/* Value if reg1 is const. */
383 : } mem_insn;
384 :
385 :
386 : /* Dump the parsed mem insn to FILE. */
387 :
388 : static void
389 0 : dump_mem_insn (FILE *file)
390 : {
391 0 : dump_insn_slim (file, mem_insn.insn);
392 :
393 0 : if (mem_insn.reg1_is_const)
394 0 : fprintf (file, "found mem(%d) *(r[%d]+%d)\n",
395 0 : INSN_UID (mem_insn.insn),
396 0 : REGNO (mem_insn.reg0), (int) mem_insn.reg1_val);
397 : else
398 0 : fprintf (file, "found mem(%d) *(r[%d]+r[%d])\n",
399 0 : INSN_UID (mem_insn.insn),
400 0 : REGNO (mem_insn.reg0), REGNO (mem_insn.reg1));
401 0 : }
402 :
403 :
404 : /* The following three arrays contain pointers to instructions. They
405 : are indexed by REGNO. At any point in the basic block where we are
406 : looking these three arrays contain, respectively, the next insn
407 : that uses REGNO, the next inc or add insn that uses REGNO and the
408 : next insn that sets REGNO.
409 :
410 : The arrays are not cleared when we move from block to block so
411 : whenever an insn is retrieved from these arrays, it's block number
412 : must be compared with the current block.
413 : */
414 :
415 : static rtx_insn **reg_next_debug_use = NULL;
416 : static rtx_insn **reg_next_use = NULL;
417 : static rtx_insn **reg_next_inc_use = NULL;
418 : static rtx_insn **reg_next_def = NULL;
419 :
420 :
421 : /* Move dead note that match PATTERN to TO_INSN from FROM_INSN. We do
422 : not really care about moving any other notes from the inc or add
423 : insn. Moving the REG_EQUAL and REG_EQUIV is clearly wrong and it
424 : does not appear that there are any other kinds of relevant notes. */
425 :
426 : static void
427 0 : move_dead_notes (rtx_insn *to_insn, rtx_insn *from_insn, rtx pattern)
428 : {
429 0 : rtx note;
430 0 : rtx next_note;
431 0 : rtx prev_note = NULL;
432 :
433 0 : for (note = REG_NOTES (from_insn); note; note = next_note)
434 : {
435 0 : next_note = XEXP (note, 1);
436 :
437 0 : if ((REG_NOTE_KIND (note) == REG_DEAD)
438 0 : && pattern == XEXP (note, 0))
439 : {
440 0 : XEXP (note, 1) = REG_NOTES (to_insn);
441 0 : REG_NOTES (to_insn) = note;
442 0 : if (prev_note)
443 0 : XEXP (prev_note, 1) = next_note;
444 : else
445 0 : REG_NOTES (from_insn) = next_note;
446 : }
447 : else prev_note = note;
448 : }
449 0 : }
450 :
451 : /* Change mem_insn.mem_loc so that uses NEW_ADDR which has an
452 : increment of INC_REG. To have reached this point, the change is a
453 : legitimate one from a dataflow point of view. The only questions
454 : are is this a valid change to the instruction and is this a
455 : profitable change to the instruction. */
456 :
457 : static bool
458 0 : attempt_change (rtx new_addr, rtx inc_reg)
459 : {
460 : /* There are four cases: For the two cases that involve an add
461 : instruction, we are going to have to delete the add and insert a
462 : mov. We are going to assume that the mov is free. This is
463 : fairly early in the backend and there are a lot of opportunities
464 : for removing that move later. In particular, there is the case
465 : where the move may be dead, this is what dead code elimination
466 : passes are for. The two cases where we have an inc insn will be
467 : handled mov free. */
468 :
469 0 : basic_block bb = BLOCK_FOR_INSN (mem_insn.insn);
470 0 : rtx_insn *mov_insn = NULL;
471 0 : int regno;
472 0 : rtx mem = *mem_insn.mem_loc;
473 0 : machine_mode mode = GET_MODE (mem);
474 0 : int align = MEM_ALIGN (mem);
475 0 : rtx new_mem;
476 0 : int old_cost = 0;
477 0 : int new_cost = 0;
478 0 : bool speed = optimize_bb_for_speed_p (bb);
479 :
480 0 : PUT_MODE (mem_tmp, mode);
481 0 : XEXP (mem_tmp, 0) = new_addr;
482 0 : set_mem_align (mem_tmp, align);
483 :
484 0 : old_cost = (set_src_cost (mem, mode, speed)
485 0 : + set_rtx_cost (PATTERN (inc_insn.insn), speed));
486 :
487 0 : new_cost = set_src_cost (mem_tmp, mode, speed);
488 :
489 : /* In the FORM_PRE_ADD and FORM_POST_ADD cases we emit an extra move
490 : whose cost we should account for. */
491 0 : if (inc_insn.form == FORM_PRE_ADD
492 0 : || inc_insn.form == FORM_POST_ADD)
493 : {
494 0 : start_sequence ();
495 0 : emit_move_insn (inc_insn.reg_res, inc_insn.reg0);
496 0 : mov_insn = end_sequence ();
497 0 : new_cost += seq_cost (mov_insn, speed);
498 : }
499 :
500 : /* The first item of business is to see if this is profitable. */
501 0 : if (old_cost < new_cost)
502 : {
503 0 : if (dump_file)
504 0 : fprintf (dump_file, "cost failure old=%d new=%d\n", old_cost, new_cost);
505 0 : return false;
506 : }
507 :
508 : /* Jump through a lot of hoops to keep the attributes up to date. We
509 : do not want to call one of the change address variants that take
510 : an offset even though we know the offset in many cases. These
511 : assume you are changing where the address is pointing by the
512 : offset. */
513 0 : new_mem = replace_equiv_address_nv (mem, new_addr);
514 0 : if (! validate_change (mem_insn.insn, mem_insn.mem_loc, new_mem, 0))
515 : {
516 0 : if (dump_file)
517 0 : fprintf (dump_file, "validation failure\n");
518 0 : return false;
519 : }
520 :
521 : /* From here to the end of the function we are committed to the
522 : change, i.e. nothing fails. Generate any necessary movs, move
523 : any regnotes, and fix up the reg_next_{use,inc_use,def}. */
524 0 : switch (inc_insn.form)
525 : {
526 0 : case FORM_PRE_ADD:
527 : /* Replace the addition with a move. Do it at the location of
528 : the addition since the operand of the addition may change
529 : before the memory reference. */
530 0 : gcc_assert (mov_insn);
531 0 : emit_insn_before (mov_insn, inc_insn.insn);
532 0 : regno = REGNO (inc_insn.reg0);
533 : /* ??? Could REGNO possibly be used in MEM_INSN other than in
534 : the MEM address, and still die there, so that move_dead_notes
535 : would incorrectly move the note? */
536 0 : if (reg_next_use[regno] == mem_insn.insn)
537 0 : move_dead_notes (mov_insn, mem_insn.insn, inc_insn.reg0);
538 : else
539 0 : move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0);
540 :
541 0 : regno = REGNO (inc_insn.reg_res);
542 0 : if (reg_next_debug_use && reg_next_debug_use[regno]
543 0 : && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb)
544 : {
545 0 : rtx adjres = gen_rtx_PLUS (GET_MODE (inc_insn.reg_res),
546 : inc_insn.reg_res, inc_insn.reg1);
547 0 : if (dump_file)
548 0 : fprintf (dump_file, "adjusting debug insns\n");
549 0 : propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
550 : mem_insn.insn,
551 : inc_insn.reg_res, adjres, bb);
552 0 : reg_next_debug_use[regno] = NULL;
553 : }
554 0 : reg_next_def[regno] = mov_insn;
555 0 : reg_next_use[regno] = NULL;
556 :
557 0 : regno = REGNO (inc_insn.reg0);
558 0 : if (reg_next_debug_use && reg_next_debug_use[regno]
559 0 : && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb
560 0 : && find_reg_note (mov_insn, REG_DEAD, inc_insn.reg0))
561 : {
562 0 : if (dump_file)
563 0 : fprintf (dump_file, "remapping debug insns\n");
564 0 : propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
565 : mem_insn.insn,
566 : inc_insn.reg0, inc_insn.reg_res, bb);
567 0 : reg_next_debug_use[regno] = NULL;
568 : }
569 0 : reg_next_use[regno] = mov_insn;
570 0 : df_recompute_luids (bb);
571 0 : break;
572 :
573 0 : case FORM_POST_INC:
574 0 : regno = REGNO (inc_insn.reg_res);
575 0 : if (reg_next_debug_use && reg_next_debug_use[regno]
576 0 : && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb)
577 : {
578 0 : rtx adjres = gen_rtx_MINUS (GET_MODE (inc_insn.reg_res),
579 : inc_insn.reg_res, inc_insn.reg1);
580 0 : if (dump_file)
581 0 : fprintf (dump_file, "adjusting debug insns\n");
582 0 : propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
583 : inc_insn.insn,
584 : inc_insn.reg_res, adjres, bb);
585 0 : reg_next_debug_use[regno] = NULL;
586 : }
587 0 : if (reg_next_use[regno] == reg_next_inc_use[regno])
588 0 : reg_next_inc_use[regno] = NULL;
589 :
590 : /* Fallthru. */
591 0 : case FORM_PRE_INC:
592 0 : regno = REGNO (inc_insn.reg_res);
593 : /* Despite the fall-through, we won't run this twice: we'll have
594 : already cleared reg_next_debug_use[regno] before falling
595 : through. */
596 0 : if (reg_next_debug_use && reg_next_debug_use[regno]
597 0 : && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb)
598 : {
599 0 : rtx adjres = gen_rtx_PLUS (GET_MODE (inc_insn.reg_res),
600 : inc_insn.reg_res, inc_insn.reg1);
601 0 : if (dump_file)
602 0 : fprintf (dump_file, "adjusting debug insns\n");
603 0 : propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
604 : mem_insn.insn,
605 : inc_insn.reg_res, adjres, bb);
606 0 : if (DF_INSN_LUID (mem_insn.insn)
607 0 : < DF_INSN_LUID (reg_next_debug_use[regno]))
608 0 : reg_next_debug_use[regno] = NULL;
609 : }
610 0 : reg_next_def[regno] = mem_insn.insn;
611 0 : reg_next_use[regno] = NULL;
612 :
613 0 : break;
614 :
615 0 : case FORM_POST_ADD:
616 0 : gcc_assert (mov_insn);
617 0 : emit_insn_before (mov_insn, mem_insn.insn);
618 0 : move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0);
619 :
620 : /* Do not move anything to the mov insn because the instruction
621 : pointer for the main iteration has not yet hit that. It is
622 : still pointing to the mem insn. */
623 0 : regno = REGNO (inc_insn.reg_res);
624 : /* The pseudo is now set earlier, so it must have been dead in
625 : that range, and dead registers cannot be referenced in debug
626 : insns. */
627 0 : gcc_assert (!(reg_next_debug_use && reg_next_debug_use[regno]
628 : && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb));
629 0 : reg_next_def[regno] = mem_insn.insn;
630 0 : reg_next_use[regno] = NULL;
631 :
632 0 : regno = REGNO (inc_insn.reg0);
633 0 : if (reg_next_debug_use && reg_next_debug_use[regno]
634 0 : && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb
635 0 : && find_reg_note (mov_insn, REG_DEAD, inc_insn.reg0))
636 : {
637 0 : if (dump_file)
638 0 : fprintf (dump_file, "remapping debug insns\n");
639 0 : propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
640 : inc_insn.insn,
641 : inc_insn.reg0, inc_insn.reg_res, bb);
642 0 : reg_next_debug_use[regno] = NULL;
643 : }
644 0 : reg_next_use[regno] = mem_insn.insn;
645 0 : if ((reg_next_use[regno] == reg_next_inc_use[regno])
646 0 : || (reg_next_inc_use[regno] == inc_insn.insn))
647 0 : reg_next_inc_use[regno] = NULL;
648 0 : df_recompute_luids (bb);
649 0 : break;
650 :
651 0 : case FORM_last:
652 0 : default:
653 0 : gcc_unreachable ();
654 : }
655 :
656 0 : if (!inc_insn.reg1_is_const)
657 : {
658 0 : regno = REGNO (inc_insn.reg1);
659 0 : reg_next_use[regno] = mem_insn.insn;
660 0 : if ((reg_next_use[regno] == reg_next_inc_use[regno])
661 0 : || (reg_next_inc_use[regno] == inc_insn.insn))
662 0 : reg_next_inc_use[regno] = NULL;
663 : }
664 :
665 0 : delete_insn (inc_insn.insn);
666 :
667 0 : if (dump_file && mov_insn)
668 : {
669 0 : fprintf (dump_file, "inserting mov ");
670 0 : dump_insn_slim (dump_file, mov_insn);
671 : }
672 :
673 : /* Record that this insn has an implicit side effect. */
674 0 : add_reg_note (mem_insn.insn, REG_INC, inc_reg);
675 :
676 0 : if (dump_file)
677 : {
678 0 : fprintf (dump_file, "****success ");
679 0 : dump_insn_slim (dump_file, mem_insn.insn);
680 : }
681 :
682 : return true;
683 : }
684 :
685 :
686 : /* Try to combine the instruction in INC_INSN with the instruction in
687 : MEM_INSN. First the form is determined using the DECISION_TABLE
688 : and the results of parsing the INC_INSN and the MEM_INSN.
689 : Assuming the form is ok, a prototype new address is built which is
690 : passed to ATTEMPT_CHANGE for final processing. */
691 :
692 : static bool
693 0 : try_merge (void)
694 : {
695 0 : enum gen_form gen_form;
696 0 : rtx mem = *mem_insn.mem_loc;
697 0 : rtx inc_reg = inc_insn.form == FORM_POST_ADD ?
698 : inc_insn.reg_res : mem_insn.reg0;
699 :
700 : /* The width of the mem being accessed. */
701 0 : poly_int64 size = GET_MODE_SIZE (GET_MODE (mem));
702 0 : rtx_insn *last_insn = NULL;
703 0 : machine_mode reg_mode = GET_MODE (inc_reg);
704 :
705 0 : switch (inc_insn.form)
706 : {
707 0 : case FORM_PRE_ADD:
708 0 : case FORM_PRE_INC:
709 0 : last_insn = mem_insn.insn;
710 0 : break;
711 0 : case FORM_POST_INC:
712 0 : case FORM_POST_ADD:
713 0 : last_insn = inc_insn.insn;
714 0 : break;
715 0 : case FORM_last:
716 0 : default:
717 0 : gcc_unreachable ();
718 : }
719 :
720 : /* Cannot handle auto inc of the stack. */
721 0 : if (inc_reg == stack_pointer_rtx)
722 : {
723 0 : if (dump_file)
724 0 : fprintf (dump_file, "cannot inc stack %d failure\n", REGNO (inc_reg));
725 0 : return false;
726 : }
727 :
728 : /* Look to see if the inc register is dead after the memory
729 : reference. If it is, do not do the combination. */
730 0 : if (find_regno_note (last_insn, REG_DEAD, REGNO (inc_reg)))
731 : {
732 0 : if (dump_file)
733 0 : fprintf (dump_file, "dead failure %d\n", REGNO (inc_reg));
734 0 : return false;
735 : }
736 :
737 0 : mem_insn.reg1_state = (mem_insn.reg1_is_const)
738 0 : ? set_inc_state (mem_insn.reg1_val, size) : INC_REG;
739 0 : inc_insn.reg1_state = (inc_insn.reg1_is_const)
740 0 : ? set_inc_state (inc_insn.reg1_val, size) : INC_REG;
741 :
742 : /* Now get the form that we are generating. */
743 0 : gen_form = decision_table
744 0 : [inc_insn.reg1_state][mem_insn.reg1_state][inc_insn.form];
745 :
746 0 : if (dbg_cnt (auto_inc_dec) == false)
747 : return false;
748 :
749 0 : switch (gen_form)
750 : {
751 : default:
752 : case NOTHING:
753 : return false;
754 :
755 0 : case SIMPLE_PRE_INC: /* ++size */
756 0 : if (dump_file)
757 0 : fprintf (dump_file, "trying SIMPLE_PRE_INC\n");
758 0 : return attempt_change (gen_rtx_PRE_INC (reg_mode, inc_reg), inc_reg);
759 :
760 0 : case SIMPLE_POST_INC: /* size++ */
761 0 : if (dump_file)
762 0 : fprintf (dump_file, "trying SIMPLE_POST_INC\n");
763 0 : return attempt_change (gen_rtx_POST_INC (reg_mode, inc_reg), inc_reg);
764 :
765 0 : case SIMPLE_PRE_DEC: /* --size */
766 0 : if (dump_file)
767 0 : fprintf (dump_file, "trying SIMPLE_PRE_DEC\n");
768 0 : return attempt_change (gen_rtx_PRE_DEC (reg_mode, inc_reg), inc_reg);
769 :
770 0 : case SIMPLE_POST_DEC: /* size-- */
771 0 : if (dump_file)
772 0 : fprintf (dump_file, "trying SIMPLE_POST_DEC\n");
773 0 : return attempt_change (gen_rtx_POST_DEC (reg_mode, inc_reg), inc_reg);
774 :
775 0 : case DISP_PRE: /* ++con */
776 0 : if (dump_file)
777 0 : fprintf (dump_file, "trying DISP_PRE\n");
778 0 : return attempt_change (gen_rtx_PRE_MODIFY (reg_mode,
779 : inc_reg,
780 : gen_rtx_PLUS (reg_mode,
781 : inc_reg,
782 : inc_insn.reg1)),
783 0 : inc_reg);
784 :
785 0 : case DISP_POST: /* con++ */
786 0 : if (dump_file)
787 0 : fprintf (dump_file, "trying POST_DISP\n");
788 0 : return attempt_change (gen_rtx_POST_MODIFY (reg_mode,
789 : inc_reg,
790 : gen_rtx_PLUS (reg_mode,
791 : inc_reg,
792 : inc_insn.reg1)),
793 0 : inc_reg);
794 :
795 0 : case REG_PRE: /* ++reg */
796 0 : if (dump_file)
797 0 : fprintf (dump_file, "trying PRE_REG\n");
798 0 : return attempt_change (gen_rtx_PRE_MODIFY (reg_mode,
799 : inc_reg,
800 : gen_rtx_PLUS (reg_mode,
801 : inc_reg,
802 : inc_insn.reg1)),
803 0 : inc_reg);
804 :
805 0 : case REG_POST: /* reg++ */
806 0 : if (dump_file)
807 0 : fprintf (dump_file, "trying POST_REG\n");
808 0 : return attempt_change (gen_rtx_POST_MODIFY (reg_mode,
809 : inc_reg,
810 : gen_rtx_PLUS (reg_mode,
811 : inc_reg,
812 : inc_insn.reg1)),
813 0 : inc_reg);
814 : }
815 : }
816 :
817 : /* Return the next insn that uses (if reg_next_use is passed in
818 : NEXT_ARRAY) or defines (if reg_next_def is passed in NEXT_ARRAY)
819 : REGNO in BB. */
820 :
821 : static rtx_insn *
822 0 : get_next_ref (int regno, basic_block bb, rtx_insn **next_array)
823 : {
824 0 : rtx_insn *insn = next_array[regno];
825 :
826 : /* Lazy about cleaning out the next_arrays. */
827 0 : if (insn && BLOCK_FOR_INSN (insn) != bb)
828 : {
829 0 : next_array[regno] = NULL;
830 0 : insn = NULL;
831 : }
832 :
833 0 : return insn;
834 : }
835 :
836 :
837 : /* Return true if INSN is of a form "a = b op c" where a and b are
838 : regs. op is + if c is a reg and +|- if c is a const. Fill in
839 : INC_INSN with what is found.
840 :
841 : This function is called in two contexts, if BEFORE_MEM is true,
842 : this is called for each insn in the basic block. If BEFORE_MEM is
843 : false, it is called for the instruction in the block that uses the
844 : index register for some memory reference that is currently being
845 : processed. */
846 :
847 : static bool
848 0 : parse_add_or_inc (rtx_insn *insn, bool before_mem)
849 : {
850 0 : rtx pat = single_set (insn);
851 0 : if (!pat)
852 : return false;
853 :
854 : /* Result must be single reg. */
855 0 : if (!REG_P (SET_DEST (pat)))
856 : return false;
857 :
858 0 : if ((GET_CODE (SET_SRC (pat)) != PLUS)
859 0 : && (GET_CODE (SET_SRC (pat)) != MINUS))
860 : return false;
861 :
862 0 : if (!REG_P (XEXP (SET_SRC (pat), 0)))
863 : return false;
864 :
865 0 : inc_insn.insn = insn;
866 0 : inc_insn.pat = pat;
867 0 : inc_insn.reg_res = SET_DEST (pat);
868 0 : inc_insn.reg0 = XEXP (SET_SRC (pat), 0);
869 :
870 : /* Block any auto increment of the frame pointer since it expands into
871 : an addition and cannot be removed by copy propagation. */
872 0 : if (inc_insn.reg0 == frame_pointer_rtx)
873 : return false;
874 :
875 0 : if (rtx_equal_p (inc_insn.reg_res, inc_insn.reg0))
876 0 : inc_insn.form = before_mem ? FORM_PRE_INC : FORM_POST_INC;
877 : else
878 0 : inc_insn.form = before_mem ? FORM_PRE_ADD : FORM_POST_ADD;
879 :
880 0 : if (CONST_INT_P (XEXP (SET_SRC (pat), 1)))
881 : {
882 : /* Process a = b + c where c is a const. */
883 0 : inc_insn.reg1_is_const = true;
884 0 : if (GET_CODE (SET_SRC (pat)) == PLUS)
885 : {
886 0 : inc_insn.reg1 = XEXP (SET_SRC (pat), 1);
887 0 : inc_insn.reg1_val = INTVAL (inc_insn.reg1);
888 : }
889 : else
890 : {
891 0 : inc_insn.reg1_val = -INTVAL (XEXP (SET_SRC (pat), 1));
892 0 : inc_insn.reg1 = GEN_INT (inc_insn.reg1_val);
893 : }
894 0 : return true;
895 : }
896 : else if ((HAVE_PRE_MODIFY_REG || HAVE_POST_MODIFY_REG)
897 : && (REG_P (XEXP (SET_SRC (pat), 1)))
898 : && GET_CODE (SET_SRC (pat)) == PLUS)
899 : {
900 : /* Process a = b + c where c is a reg. */
901 : inc_insn.reg1 = XEXP (SET_SRC (pat), 1);
902 : inc_insn.reg1_is_const = false;
903 :
904 : if (inc_insn.form == FORM_PRE_INC
905 : || inc_insn.form == FORM_POST_INC)
906 : return true;
907 : else if (rtx_equal_p (inc_insn.reg_res, inc_insn.reg1))
908 : {
909 : /* Reverse the two operands and turn *_ADD into *_INC since
910 : a = c + a. */
911 : std::swap (inc_insn.reg0, inc_insn.reg1);
912 : inc_insn.form = before_mem ? FORM_PRE_INC : FORM_POST_INC;
913 : return true;
914 : }
915 : else
916 : return true;
917 : }
918 :
919 : return false;
920 : }
921 :
922 :
923 : /* A recursive function that checks all of the mem uses in
924 : ADDRESS_OF_X to see if any single one of them is compatible with
925 : what has been found in inc_insn. To avoid accidental matches, we
926 : will only find MEMs with FINDREG, be it inc_insn.reg_res, be it
927 : inc_insn.reg0.
928 :
929 : -1 is returned for success. 0 is returned if nothing was found and
930 : 1 is returned for failure. */
931 :
932 : static int
933 0 : find_address (rtx *address_of_x, rtx findreg)
934 : {
935 0 : rtx x = *address_of_x;
936 0 : enum rtx_code code = GET_CODE (x);
937 0 : const char *const fmt = GET_RTX_FORMAT (code);
938 0 : int i;
939 0 : int value = 0;
940 0 : int tem;
941 :
942 0 : if (code == MEM && findreg == inc_insn.reg_res
943 0 : && rtx_equal_p (XEXP (x, 0), inc_insn.reg_res))
944 : {
945 : /* Match with *reg_res. */
946 0 : mem_insn.mem_loc = address_of_x;
947 0 : mem_insn.reg0 = inc_insn.reg_res;
948 0 : mem_insn.reg1_is_const = true;
949 0 : mem_insn.reg1_val = 0;
950 0 : mem_insn.reg1 = GEN_INT (0);
951 0 : return -1;
952 : }
953 0 : if (code == MEM && inc_insn.reg1_is_const && inc_insn.reg0
954 0 : && findreg == inc_insn.reg0
955 0 : && rtx_equal_p (XEXP (x, 0), inc_insn.reg0))
956 : {
957 : /* Match with *reg0, assumed to be equivalent to
958 : *(reg_res - reg1_val); callers must check whether this is the case. */
959 0 : mem_insn.mem_loc = address_of_x;
960 0 : mem_insn.reg0 = inc_insn.reg_res;
961 0 : mem_insn.reg1_is_const = true;
962 0 : mem_insn.reg1_val = -inc_insn.reg1_val;
963 0 : mem_insn.reg1 = GEN_INT (mem_insn.reg1_val);
964 0 : return -1;
965 : }
966 0 : if (code == MEM && findreg == inc_insn.reg_res
967 0 : && GET_CODE (XEXP (x, 0)) == PLUS
968 0 : && rtx_equal_p (XEXP (XEXP (x, 0), 0), inc_insn.reg_res))
969 : {
970 0 : rtx b = XEXP (XEXP (x, 0), 1);
971 0 : mem_insn.mem_loc = address_of_x;
972 0 : mem_insn.reg0 = inc_insn.reg_res;
973 0 : mem_insn.reg1 = b;
974 0 : mem_insn.reg1_is_const = inc_insn.reg1_is_const;
975 0 : if (CONST_INT_P (b))
976 : {
977 : /* Match with *(reg0 + reg1) where reg1 is a const. */
978 0 : HOST_WIDE_INT val = INTVAL (b);
979 0 : if (inc_insn.reg1_is_const
980 0 : && (inc_insn.reg1_val == val || inc_insn.reg1_val == -val))
981 : {
982 0 : mem_insn.reg1_val = val;
983 0 : return -1;
984 : }
985 : }
986 0 : else if (!inc_insn.reg1_is_const
987 0 : && rtx_equal_p (inc_insn.reg1, b))
988 : /* Match with *(reg0 + reg1). */
989 : return -1;
990 : }
991 :
992 0 : if (code == SIGN_EXTRACT || code == ZERO_EXTRACT)
993 : {
994 : /* If REG occurs inside a MEM used in a bit-field reference,
995 : that is unacceptable. */
996 0 : if (find_address (&XEXP (x, 0), findreg))
997 : return 1;
998 : }
999 :
1000 0 : if (x == inc_insn.reg_res)
1001 : return 1;
1002 :
1003 : /* Time for some deep diving. */
1004 0 : for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
1005 : {
1006 0 : if (fmt[i] == 'e')
1007 : {
1008 0 : tem = find_address (&XEXP (x, i), findreg);
1009 : /* If this is the first use, let it go so the rest of the
1010 : insn can be checked. */
1011 0 : if (value == 0)
1012 : value = tem;
1013 0 : else if (tem != 0)
1014 : /* More than one match was found. */
1015 : return 1;
1016 : }
1017 0 : else if (fmt[i] == 'E')
1018 : {
1019 0 : int j;
1020 0 : for (j = XVECLEN (x, i) - 1; j >= 0; j--)
1021 : {
1022 0 : tem = find_address (&XVECEXP (x, i, j), findreg);
1023 : /* If this is the first use, let it go so the rest of
1024 : the insn can be checked. */
1025 0 : if (value == 0)
1026 : value = tem;
1027 0 : else if (tem != 0)
1028 : /* More than one match was found. */
1029 : return 1;
1030 : }
1031 : }
1032 : }
1033 : return value;
1034 : }
1035 :
1036 : /* Once a suitable mem reference has been found and the MEM_INSN
1037 : structure has been filled in, FIND_INC is called to see if there is
1038 : a suitable add or inc insn that follows the mem reference and
1039 : determine if it is suitable to merge.
1040 :
1041 : In the case where the MEM_INSN has two registers in the reference,
1042 : this function may be called recursively. The first time looking
1043 : for an add of the first register, and if that fails, looking for an
1044 : add of the second register. The FIRST_TRY parameter is used to
1045 : only allow the parameters to be reversed once. */
1046 :
1047 : static bool
1048 0 : find_inc (bool first_try)
1049 : {
1050 0 : rtx_insn *insn;
1051 0 : basic_block bb = BLOCK_FOR_INSN (mem_insn.insn);
1052 0 : rtx_insn *other_insn;
1053 0 : df_ref def;
1054 :
1055 : /* Make sure this reg appears only once in this insn. */
1056 0 : if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg0, 1) != 1)
1057 : {
1058 0 : if (dump_file)
1059 0 : fprintf (dump_file, "mem count failure\n");
1060 0 : return false;
1061 : }
1062 :
1063 0 : if (dump_file)
1064 0 : dump_mem_insn (dump_file);
1065 :
1066 : /* Find the next use that is an inc. */
1067 0 : insn = get_next_ref (REGNO (mem_insn.reg0),
1068 0 : BLOCK_FOR_INSN (mem_insn.insn),
1069 : reg_next_inc_use);
1070 0 : if (!insn)
1071 0 : return false;
1072 :
1073 : /* Even though we know the next use is an add or inc because it came
1074 : from the reg_next_inc_use, we must still reparse. */
1075 0 : if (!parse_add_or_inc (insn, false))
1076 : {
1077 : /* Next use was not an add. Look for one extra case. It could be
1078 : that we have:
1079 :
1080 : *(a + b)
1081 : ...= a;
1082 : ...= b + a
1083 :
1084 : if we reverse the operands in the mem ref we would
1085 : find this. Only try it once though. */
1086 0 : if (first_try && !mem_insn.reg1_is_const)
1087 : {
1088 0 : std::swap (mem_insn.reg0, mem_insn.reg1);
1089 0 : return find_inc (false);
1090 : }
1091 : else
1092 : return false;
1093 : }
1094 :
1095 : /* Need to assure that none of the operands of the inc instruction are
1096 : assigned to by the mem insn. */
1097 0 : FOR_EACH_INSN_DEF (def, mem_insn.insn)
1098 : {
1099 0 : unsigned int regno = DF_REF_REGNO (def);
1100 0 : if ((regno == REGNO (inc_insn.reg0))
1101 0 : || (regno == REGNO (inc_insn.reg_res)))
1102 : {
1103 0 : if (dump_file)
1104 0 : fprintf (dump_file, "inc conflicts with store failure.\n");
1105 0 : return false;
1106 : }
1107 0 : if (!inc_insn.reg1_is_const && (regno == REGNO (inc_insn.reg1)))
1108 : {
1109 0 : if (dump_file)
1110 0 : fprintf (dump_file, "inc conflicts with store failure.\n");
1111 0 : return false;
1112 : }
1113 : }
1114 :
1115 0 : if (dump_file)
1116 0 : dump_inc_insn (dump_file);
1117 :
1118 0 : if (inc_insn.form == FORM_POST_ADD)
1119 : {
1120 : /* Make sure that there is no insn that assigns to inc_insn.res
1121 : between the mem_insn and the inc_insn. */
1122 0 : rtx_insn *other_insn = get_next_ref (REGNO (inc_insn.reg_res),
1123 0 : BLOCK_FOR_INSN (mem_insn.insn),
1124 : reg_next_def);
1125 0 : if (other_insn != inc_insn.insn)
1126 : {
1127 0 : if (dump_file)
1128 0 : fprintf (dump_file,
1129 : "result of add is assigned to between mem and inc insns.\n");
1130 0 : return false;
1131 : }
1132 :
1133 0 : other_insn = get_next_ref (REGNO (inc_insn.reg_res),
1134 0 : BLOCK_FOR_INSN (mem_insn.insn),
1135 : reg_next_use);
1136 0 : if (other_insn
1137 0 : && (other_insn != inc_insn.insn)
1138 0 : && (DF_INSN_LUID (inc_insn.insn) > DF_INSN_LUID (other_insn)))
1139 : {
1140 0 : if (dump_file)
1141 0 : fprintf (dump_file,
1142 : "result of add is used between mem and inc insns.\n");
1143 0 : return false;
1144 : }
1145 :
1146 : /* For the post_add to work, the result_reg of the inc must not be
1147 : used in the mem insn since this will become the new index
1148 : register. */
1149 0 : if (reg_overlap_mentioned_p (inc_insn.reg_res, PATTERN (mem_insn.insn)))
1150 : {
1151 0 : if (dump_file)
1152 0 : fprintf (dump_file, "base reg replacement failure.\n");
1153 0 : return false;
1154 : }
1155 : }
1156 :
1157 0 : if (mem_insn.reg1_is_const)
1158 : {
1159 0 : if (mem_insn.reg1_val == 0)
1160 : {
1161 0 : if (!inc_insn.reg1_is_const)
1162 : {
1163 : /* The mem looks like *r0 and the rhs of the add has two
1164 : registers. */
1165 0 : int luid = DF_INSN_LUID (inc_insn.insn);
1166 0 : if (inc_insn.form == FORM_POST_ADD)
1167 : {
1168 : /* The trick is that we are not going to increment r0,
1169 : we are going to increment the result of the add insn.
1170 : For this trick to be correct, the result reg of
1171 : the inc must be a valid addressing reg. */
1172 0 : addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc);
1173 0 : if (GET_MODE (inc_insn.reg_res)
1174 0 : != targetm.addr_space.address_mode (as))
1175 : {
1176 0 : if (dump_file)
1177 0 : fprintf (dump_file, "base reg mode failure.\n");
1178 0 : return false;
1179 : }
1180 :
1181 : /* We also need to make sure that the next use of
1182 : inc result is after the inc. */
1183 0 : other_insn
1184 0 : = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_use);
1185 0 : if (other_insn && luid > DF_INSN_LUID (other_insn))
1186 : return false;
1187 :
1188 0 : if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0))
1189 0 : std::swap (inc_insn.reg0, inc_insn.reg1);
1190 : }
1191 :
1192 0 : other_insn
1193 0 : = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
1194 0 : if (other_insn && luid > DF_INSN_LUID (other_insn))
1195 : return false;
1196 : }
1197 : }
1198 : /* Both the inc/add and the mem have a constant. Need to check
1199 : that the constants are ok. */
1200 0 : else if ((mem_insn.reg1_val != inc_insn.reg1_val)
1201 0 : && (mem_insn.reg1_val != -inc_insn.reg1_val))
1202 : return false;
1203 : }
1204 : else
1205 : {
1206 : /* The mem insn is of the form *(a + b) where a and b are both
1207 : regs. It may be that in order to match the add or inc we
1208 : need to treat it as if it was *(b + a). It may also be that
1209 : the add is of the form a + c where c does not match b and
1210 : then we just abandon this. */
1211 :
1212 0 : int luid = DF_INSN_LUID (inc_insn.insn);
1213 0 : rtx_insn *other_insn;
1214 :
1215 : /* Make sure this reg appears only once in this insn. */
1216 0 : if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg1, 1) != 1)
1217 : return false;
1218 :
1219 0 : if (inc_insn.form == FORM_POST_ADD)
1220 : {
1221 : /* For this trick to be correct, the result reg of the inc
1222 : must be a valid addressing reg. */
1223 0 : addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc);
1224 0 : if (GET_MODE (inc_insn.reg_res)
1225 0 : != targetm.addr_space.address_mode (as))
1226 : {
1227 0 : if (dump_file)
1228 0 : fprintf (dump_file, "base reg mode failure.\n");
1229 0 : return false;
1230 : }
1231 :
1232 0 : if (rtx_equal_p (mem_insn.reg0, inc_insn.reg0))
1233 : {
1234 0 : if (!rtx_equal_p (mem_insn.reg1, inc_insn.reg1))
1235 : {
1236 : /* See comment above on find_inc (false) call. */
1237 0 : if (first_try)
1238 : {
1239 0 : std::swap (mem_insn.reg0, mem_insn.reg1);
1240 0 : return find_inc (false);
1241 : }
1242 : else
1243 : return false;
1244 : }
1245 :
1246 : /* Need to check that there are no assignments to b
1247 : before the add insn. */
1248 0 : other_insn
1249 0 : = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
1250 0 : if (other_insn && luid > DF_INSN_LUID (other_insn))
1251 : return false;
1252 : /* All ok for the next step. */
1253 : }
1254 : else
1255 : {
1256 : /* We know that mem_insn.reg0 must equal inc_insn.reg1
1257 : or else we would not have found the inc insn. */
1258 0 : std::swap (mem_insn.reg0, mem_insn.reg1);
1259 0 : if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0))
1260 : {
1261 : /* See comment above on find_inc (false) call. */
1262 0 : if (first_try)
1263 0 : return find_inc (false);
1264 : else
1265 : return false;
1266 : }
1267 : /* To have gotten here know that.
1268 : *(b + a)
1269 :
1270 : ... = (b + a)
1271 :
1272 : We also know that the lhs of the inc is not b or a. We
1273 : need to make sure that there are no assignments to b
1274 : between the mem ref and the inc. */
1275 :
1276 0 : other_insn
1277 0 : = get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_def);
1278 0 : if (other_insn && luid > DF_INSN_LUID (other_insn))
1279 : return false;
1280 : }
1281 :
1282 : /* Need to check that the next use of the add result is later than
1283 : add insn since this will be the reg incremented. */
1284 0 : other_insn
1285 0 : = get_next_ref (REGNO (inc_insn.reg_res), bb, reg_next_use);
1286 0 : if (other_insn && luid > DF_INSN_LUID (other_insn))
1287 : return false;
1288 : }
1289 : else /* FORM_POST_INC. There is less to check here because we
1290 : know that operands must line up. */
1291 : {
1292 0 : if (!rtx_equal_p (mem_insn.reg1, inc_insn.reg1))
1293 : /* See comment above on find_inc (false) call. */
1294 : {
1295 0 : if (first_try)
1296 : {
1297 0 : std::swap (mem_insn.reg0, mem_insn.reg1);
1298 0 : return find_inc (false);
1299 : }
1300 : else
1301 : return false;
1302 : }
1303 :
1304 : /* To have gotten here know that.
1305 : *(a + b)
1306 :
1307 : ... = (a + b)
1308 :
1309 : We also know that the lhs of the inc is not b. We need to make
1310 : sure that there are no assignments to b between the mem ref and
1311 : the inc. */
1312 0 : other_insn
1313 0 : = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
1314 0 : if (other_insn && luid > DF_INSN_LUID (other_insn))
1315 : return false;
1316 : }
1317 : }
1318 :
1319 0 : if (inc_insn.form == FORM_POST_INC)
1320 : {
1321 0 : other_insn
1322 0 : = get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_use);
1323 : /* When we found inc_insn, we were looking for the
1324 : next add or inc, not the next insn that used the
1325 : reg. Because we are going to increment the reg
1326 : in this form, we need to make sure that there
1327 : were no intervening uses of reg. */
1328 0 : if (inc_insn.insn != other_insn)
1329 : return false;
1330 : }
1331 :
1332 0 : return try_merge ();
1333 : }
1334 :
1335 :
1336 : /* A recursive function that walks ADDRESS_OF_X to find all of the mem
1337 : uses in pat that could be used as an auto inc or dec. It then
1338 : calls FIND_INC for each one. */
1339 :
1340 : static bool
1341 0 : find_mem (rtx *address_of_x)
1342 : {
1343 0 : rtx x = *address_of_x;
1344 0 : enum rtx_code code = GET_CODE (x);
1345 0 : const char *const fmt = GET_RTX_FORMAT (code);
1346 0 : int i;
1347 :
1348 0 : if (code == MEM && REG_P (XEXP (x, 0)))
1349 : {
1350 : /* Match with *reg0. */
1351 0 : mem_insn.mem_loc = address_of_x;
1352 0 : mem_insn.reg0 = XEXP (x, 0);
1353 0 : mem_insn.reg1_is_const = true;
1354 0 : mem_insn.reg1_val = 0;
1355 0 : mem_insn.reg1 = GEN_INT (0);
1356 0 : if (find_inc (true))
1357 : return true;
1358 : }
1359 0 : if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS
1360 0 : && REG_P (XEXP (XEXP (x, 0), 0)))
1361 : {
1362 0 : rtx reg1 = XEXP (XEXP (x, 0), 1);
1363 0 : mem_insn.mem_loc = address_of_x;
1364 0 : mem_insn.reg0 = XEXP (XEXP (x, 0), 0);
1365 0 : mem_insn.reg1 = reg1;
1366 0 : if (CONST_INT_P (reg1))
1367 : {
1368 0 : mem_insn.reg1_is_const = true;
1369 : /* Match with *(reg0 + c) where c is a const. */
1370 0 : mem_insn.reg1_val = INTVAL (reg1);
1371 0 : if (find_inc (true))
1372 : return true;
1373 : }
1374 0 : else if (REG_P (reg1))
1375 : {
1376 : /* Match with *(reg0 + reg1). */
1377 0 : mem_insn.reg1_is_const = false;
1378 0 : if (find_inc (true))
1379 : return true;
1380 : }
1381 : }
1382 :
1383 0 : if (code == SIGN_EXTRACT || code == ZERO_EXTRACT)
1384 : {
1385 : /* If REG occurs inside a MEM used in a bit-field reference,
1386 : that is unacceptable. */
1387 : return false;
1388 : }
1389 :
1390 : /* Time for some deep diving. */
1391 0 : for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
1392 : {
1393 0 : if (fmt[i] == 'e')
1394 : {
1395 0 : if (find_mem (&XEXP (x, i)))
1396 : return true;
1397 : }
1398 0 : else if (fmt[i] == 'E')
1399 : {
1400 0 : int j;
1401 0 : for (j = XVECLEN (x, i) - 1; j >= 0; j--)
1402 0 : if (find_mem (&XVECEXP (x, i, j)))
1403 : return true;
1404 : }
1405 : }
1406 : return false;
1407 : }
1408 :
1409 :
1410 : /* Try to combine all incs and decs by constant values with memory
1411 : references in BB. */
1412 :
1413 : static void
1414 0 : merge_in_block (int max_reg, basic_block bb)
1415 : {
1416 0 : rtx_insn *insn;
1417 0 : rtx_insn *curr;
1418 0 : int success_in_block = 0;
1419 :
1420 0 : if (dump_file)
1421 0 : fprintf (dump_file, "\n\nstarting bb %d\n", bb->index);
1422 :
1423 0 : FOR_BB_INSNS_REVERSE_SAFE (bb, insn, curr)
1424 : {
1425 0 : bool insn_is_add_or_inc = true;
1426 :
1427 0 : if (!NONDEBUG_INSN_P (insn))
1428 : {
1429 0 : if (DEBUG_BIND_INSN_P (insn))
1430 : {
1431 0 : df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
1432 0 : df_ref use;
1433 :
1434 0 : if (dump_file)
1435 0 : dump_insn_slim (dump_file, insn);
1436 :
1437 0 : FOR_EACH_INSN_INFO_USE (use, insn_info)
1438 0 : reg_next_debug_use[DF_REF_REGNO (use)] = insn;
1439 : }
1440 0 : continue;
1441 0 : }
1442 :
1443 : /* Reload should handle auto-inc within a jump correctly, while LRA
1444 : is known to have issues with autoinc. */
1445 0 : if (JUMP_P (insn) && targetm.lra_p ())
1446 0 : continue;
1447 :
1448 0 : if (dump_file)
1449 0 : dump_insn_slim (dump_file, insn);
1450 :
1451 : /* Does this instruction increment or decrement a register? */
1452 0 : if (parse_add_or_inc (insn, true))
1453 : {
1454 0 : int regno = REGNO (inc_insn.reg_res);
1455 : /* Cannot handle case where there are three separate regs
1456 : before a mem ref. Too many moves would be needed to be
1457 : profitable. */
1458 0 : if ((inc_insn.form == FORM_PRE_INC) || inc_insn.reg1_is_const)
1459 : {
1460 0 : mem_insn.insn = get_next_ref (regno, bb, reg_next_use);
1461 0 : if (mem_insn.insn)
1462 : {
1463 0 : bool ok = true;
1464 0 : if (!inc_insn.reg1_is_const)
1465 : {
1466 : /* We are only here if we are going to try a
1467 : HAVE_*_MODIFY_REG type transformation. c is a
1468 : reg and we must sure that the path from the
1469 : inc_insn to the mem_insn.insn is both def and use
1470 : clear of c because the inc insn is going to move
1471 : into the mem_insn.insn. */
1472 0 : int luid = DF_INSN_LUID (mem_insn.insn);
1473 0 : rtx_insn *other_insn
1474 0 : = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_use);
1475 :
1476 0 : if (other_insn && luid > DF_INSN_LUID (other_insn))
1477 : ok = false;
1478 :
1479 0 : other_insn
1480 0 : = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
1481 :
1482 0 : if (other_insn && luid > DF_INSN_LUID (other_insn))
1483 : ok = false;
1484 : }
1485 :
1486 0 : if (dump_file)
1487 0 : dump_inc_insn (dump_file);
1488 :
1489 0 : if (ok && find_address (&PATTERN (mem_insn.insn),
1490 : inc_insn.reg_res) == -1)
1491 : {
1492 0 : if (dump_file)
1493 0 : dump_mem_insn (dump_file);
1494 0 : if (try_merge ())
1495 : {
1496 0 : success_in_block++;
1497 0 : insn_is_add_or_inc = false;
1498 : }
1499 : }
1500 : }
1501 :
1502 0 : if (insn_is_add_or_inc
1503 : /* find_address will only recognize an address
1504 : with a reg0 that's not reg_res when
1505 : reg1_is_const, so cut it off early if we
1506 : already know it won't match. */
1507 0 : && inc_insn.reg1_is_const
1508 0 : && inc_insn.reg0
1509 0 : && inc_insn.reg0 != inc_insn.reg_res)
1510 : {
1511 : /* If we identified an inc_insn that uses two
1512 : different pseudos, it's of the form
1513 :
1514 : (set reg_res (plus reg0 reg1))
1515 :
1516 : where reg1 is a constant (*).
1517 :
1518 : The next use of reg_res was not identified by
1519 : find_address as a mem_insn that we could turn
1520 : into auto-inc, so see if we find a suitable
1521 : MEM in the next use of reg0, as long as it's
1522 : before any subsequent use of reg_res:
1523 :
1524 : ... (mem (... reg0 ...)) ...
1525 :
1526 : ... reg_res ...
1527 :
1528 : In this case, we can turn the plus into a
1529 : copy, and the reg0 in the MEM address into a
1530 : post_inc of reg_res:
1531 :
1532 : (set reg_res reg0)
1533 :
1534 : ... (mem (... (post_add reg_res reg1) ...)) ...
1535 :
1536 : reg_res will then have the correct value at
1537 : subsequent uses, and reg0 will remain
1538 : unchanged.
1539 :
1540 : (*) We could support non-const reg1, but then
1541 : we'd have to check that reg1 remains
1542 : unchanged all the way to the modified MEM,
1543 : and we'd have to extend find_address to
1544 : represent a non-const negated reg1. */
1545 0 : regno = REGNO (inc_insn.reg0);
1546 0 : rtx_insn *reg0_use = get_next_ref (regno, bb,
1547 : reg_next_use);
1548 :
1549 : /* Give up if the next use of reg0 is after the next
1550 : use of reg_res (same insn is ok; we might have
1551 : found a MEM with reg_res before, and that failed,
1552 : but now we try reg0, which might work), or defs
1553 : of reg_res (same insn is not ok, we'd introduce
1554 : another def in the same insn) or reg0. */
1555 0 : if (reg0_use)
1556 : {
1557 0 : int luid = DF_INSN_LUID (reg0_use);
1558 :
1559 : /* It might seem pointless to introduce an
1560 : auto-inc if there's no subsequent use of
1561 : reg_res (i.e., mem_insn.insn == NULL), but
1562 : the next use might be in the next iteration
1563 : of a loop, and it won't hurt if we make the
1564 : change even if it's not needed. */
1565 0 : if (mem_insn.insn
1566 0 : && luid > DF_INSN_LUID (mem_insn.insn))
1567 : reg0_use = NULL;
1568 :
1569 0 : rtx_insn *other_insn
1570 0 : = get_next_ref (REGNO (inc_insn.reg_res), bb,
1571 : reg_next_def);
1572 :
1573 0 : if (other_insn && luid >= DF_INSN_LUID (other_insn))
1574 : reg0_use = NULL;
1575 :
1576 0 : other_insn
1577 0 : = get_next_ref (REGNO (inc_insn.reg0), bb,
1578 : reg_next_def);
1579 :
1580 0 : if (other_insn && luid > DF_INSN_LUID (other_insn))
1581 : reg0_use = NULL;
1582 : }
1583 :
1584 0 : mem_insn.insn = reg0_use;
1585 :
1586 0 : if (mem_insn.insn
1587 0 : && find_address (&PATTERN (mem_insn.insn),
1588 : inc_insn.reg0) == -1)
1589 : {
1590 0 : if (dump_file)
1591 0 : dump_mem_insn (dump_file);
1592 0 : if (try_merge ())
1593 : {
1594 0 : success_in_block++;
1595 0 : insn_is_add_or_inc = false;
1596 : }
1597 : }
1598 : }
1599 : }
1600 : }
1601 : else
1602 : {
1603 0 : insn_is_add_or_inc = false;
1604 : /* We can't use auto inc/dec for bare USEs and CLOBBERs,
1605 : since they aren't supposed to generate any code. */
1606 0 : rtx_code code = GET_CODE (PATTERN (insn));
1607 0 : if (code != USE && code != CLOBBER)
1608 : {
1609 0 : mem_insn.insn = insn;
1610 0 : if (find_mem (&PATTERN (insn)))
1611 0 : success_in_block++;
1612 : }
1613 : }
1614 :
1615 : /* If the inc insn was merged with a mem, the inc insn is gone
1616 : and there is noting to update. */
1617 0 : if (df_insn_info *insn_info = DF_INSN_INFO_GET (insn))
1618 : {
1619 0 : df_ref def, use;
1620 :
1621 : /* Need to update next use. */
1622 0 : FOR_EACH_INSN_INFO_DEF (def, insn_info)
1623 : {
1624 0 : if (reg_next_debug_use)
1625 0 : reg_next_debug_use[DF_REF_REGNO (def)] = NULL;
1626 0 : reg_next_use[DF_REF_REGNO (def)] = NULL;
1627 0 : reg_next_inc_use[DF_REF_REGNO (def)] = NULL;
1628 0 : reg_next_def[DF_REF_REGNO (def)] = insn;
1629 : }
1630 :
1631 0 : FOR_EACH_INSN_INFO_USE (use, insn_info)
1632 : {
1633 0 : if (reg_next_debug_use)
1634 : /* This may seem surprising, but we know we may only
1635 : modify the value of a REG between an insn and the
1636 : next nondebug use thereof. Any debug uses after
1637 : the next nondebug use can be left alone, the REG
1638 : will hold the expected value there. */
1639 0 : reg_next_debug_use[DF_REF_REGNO (use)] = NULL;
1640 0 : reg_next_use[DF_REF_REGNO (use)] = insn;
1641 0 : if (insn_is_add_or_inc)
1642 0 : reg_next_inc_use[DF_REF_REGNO (use)] = insn;
1643 : else
1644 0 : reg_next_inc_use[DF_REF_REGNO (use)] = NULL;
1645 : }
1646 : }
1647 0 : else if (dump_file)
1648 0 : fprintf (dump_file, "skipping update of deleted insn %d\n",
1649 : INSN_UID (insn));
1650 : }
1651 :
1652 : /* If we were successful, try again. There may have been several
1653 : opportunities that were interleaved. This is rare but
1654 : gcc.c-torture/compile/pr17273.c actually exhibits this. */
1655 0 : if (success_in_block)
1656 : {
1657 : /* In this case, we must clear these vectors since the trick of
1658 : testing if the stale insn in the block will not work. */
1659 0 : if (reg_next_debug_use)
1660 0 : memset (reg_next_debug_use, 0, max_reg * sizeof (rtx));
1661 0 : memset (reg_next_use, 0, max_reg * sizeof (rtx));
1662 0 : memset (reg_next_inc_use, 0, max_reg * sizeof (rtx));
1663 0 : memset (reg_next_def, 0, max_reg * sizeof (rtx));
1664 0 : df_recompute_luids (bb);
1665 0 : merge_in_block (max_reg, bb);
1666 : }
1667 0 : }
1668 :
1669 : /* Discover auto-inc auto-dec instructions. */
1670 :
1671 : namespace {
1672 :
1673 : const pass_data pass_data_inc_dec =
1674 : {
1675 : RTL_PASS, /* type */
1676 : "auto_inc_dec", /* name */
1677 : OPTGROUP_NONE, /* optinfo_flags */
1678 : TV_AUTO_INC_DEC, /* tv_id */
1679 : 0, /* properties_required */
1680 : 0, /* properties_provided */
1681 : 0, /* properties_destroyed */
1682 : 0, /* todo_flags_start */
1683 : TODO_df_finish, /* todo_flags_finish */
1684 : };
1685 :
1686 : class pass_inc_dec : public rtl_opt_pass
1687 : {
1688 : public:
1689 285722 : pass_inc_dec (gcc::context *ctxt)
1690 571444 : : rtl_opt_pass (pass_data_inc_dec, ctxt)
1691 : {}
1692 :
1693 : /* opt_pass methods: */
1694 1471370 : bool gate (function *) final override
1695 : {
1696 1471370 : if (!AUTO_INC_DEC)
1697 1471370 : return false;
1698 :
1699 : return (optimize > 0 && flag_auto_inc_dec);
1700 : }
1701 :
1702 :
1703 : unsigned int execute (function *) final override;
1704 :
1705 : }; // class pass_inc_dec
1706 :
1707 : unsigned int
1708 0 : pass_inc_dec::execute (function *fun ATTRIBUTE_UNUSED)
1709 : {
1710 0 : if (!AUTO_INC_DEC)
1711 0 : return 0;
1712 :
1713 : basic_block bb;
1714 : int max_reg = max_reg_num ();
1715 :
1716 : if (!initialized)
1717 : init_decision_table ();
1718 :
1719 : mem_tmp = gen_rtx_MEM (Pmode, NULL_RTX);
1720 :
1721 : df_note_add_problem ();
1722 : df_analyze ();
1723 :
1724 : if (MAY_HAVE_DEBUG_BIND_INSNS)
1725 : reg_next_debug_use = XCNEWVEC (rtx_insn *, max_reg);
1726 : else
1727 : /* An earlier function may have had debug binds. */
1728 : reg_next_debug_use = NULL;
1729 : reg_next_use = XCNEWVEC (rtx_insn *, max_reg);
1730 : reg_next_inc_use = XCNEWVEC (rtx_insn *, max_reg);
1731 : reg_next_def = XCNEWVEC (rtx_insn *, max_reg);
1732 : FOR_EACH_BB_FN (bb, fun)
1733 : merge_in_block (max_reg, bb);
1734 :
1735 : free (reg_next_debug_use);
1736 : free (reg_next_use);
1737 : free (reg_next_inc_use);
1738 : free (reg_next_def);
1739 :
1740 : mem_tmp = NULL;
1741 :
1742 : return 0;
1743 : }
1744 :
1745 : } // anon namespace
1746 :
1747 : rtl_opt_pass *
1748 285722 : make_pass_inc_dec (gcc::context *ctxt)
1749 : {
1750 285722 : return new pass_inc_dec (ctxt);
1751 : }
|