tree-optimization/113126 - vector extension compare optimization
[official-gcc.git] / gcc / combine-stack-adj.cc
blob2da9bf2bc1ef25e4ba790d61193bd40b84c45ea9
1 /* Combine stack adjustments.
2 Copyright (C) 1987-2024 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.
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/>. */
20 /* Track stack adjustments and stack memory references. Attempt to
21 reduce the number of stack adjustments by back-propagating across
22 the memory references.
24 This is intended primarily for use with targets that do not define
25 ACCUMULATE_OUTGOING_ARGS. It is of significantly more value to
26 targets that define PREFERRED_STACK_BOUNDARY more aligned than
27 STACK_BOUNDARY (e.g. x86), or if not all registers can be pushed
28 (e.g. x86 fp regs) which would ordinarily have to be implemented
29 as a sub/mov pair due to restrictions in calls.cc.
31 Propagation stops when any of the insns that need adjusting are
32 (a) no longer valid because we've exceeded their range, (b) a
33 non-trivial push instruction, or (c) a call instruction.
35 Restriction B is based on the assumption that push instructions
36 are smaller or faster. If a port really wants to remove all
37 pushes, it should have defined ACCUMULATE_OUTGOING_ARGS. The
38 one exception that is made is for an add immediately followed
39 by a push. */
41 #include "config.h"
42 #include "system.h"
43 #include "coretypes.h"
44 #include "backend.h"
45 #include "rtl.h"
46 #include "df.h"
47 #include "insn-config.h"
48 #include "memmodel.h"
49 #include "emit-rtl.h"
50 #include "recog.h"
51 #include "cfgrtl.h"
52 #include "tree-pass.h"
53 #include "rtl-iter.h"
56 /* This structure records two kinds of stack references between stack
57 adjusting instructions: stack references in memory addresses for
58 regular insns and all stack references for debug insns. */
60 struct csa_reflist
62 HOST_WIDE_INT sp_offset;
63 rtx_insn *insn;
64 rtx *ref;
65 struct csa_reflist *next;
68 static bool stack_memref_p (rtx);
69 static rtx single_set_for_csa (rtx_insn *);
70 static void free_csa_reflist (struct csa_reflist *);
71 static struct csa_reflist *record_one_stack_ref (rtx_insn *, rtx *,
72 struct csa_reflist *);
73 static bool try_apply_stack_adjustment (rtx_insn *, struct csa_reflist *,
74 HOST_WIDE_INT, HOST_WIDE_INT,
75 bitmap, rtx_insn *);
76 static void combine_stack_adjustments_for_block (basic_block, bitmap);
79 /* Main entry point for stack adjustment combination. */
81 static void
82 combine_stack_adjustments (void)
84 basic_block bb;
85 bitmap live = BITMAP_ALLOC (&reg_obstack);
87 FOR_EACH_BB_FN (bb, cfun)
88 combine_stack_adjustments_for_block (bb, live);
90 BITMAP_FREE (live);
93 /* Recognize a MEM of the form (sp) or (plus sp const). */
95 static bool
96 stack_memref_p (rtx x)
98 if (!MEM_P (x))
99 return false;
100 x = XEXP (x, 0);
102 if (x == stack_pointer_rtx)
103 return true;
104 if (GET_CODE (x) == PLUS
105 && XEXP (x, 0) == stack_pointer_rtx
106 && CONST_INT_P (XEXP (x, 1)))
107 return true;
109 return false;
112 /* Recognize either normal single_set or the hack in i386.md for
113 tying fp and sp adjustments. */
115 static rtx
116 single_set_for_csa (rtx_insn *insn)
118 int i;
119 rtx tmp = single_set (insn);
120 if (tmp)
121 return tmp;
123 if (!NONJUMP_INSN_P (insn)
124 || GET_CODE (PATTERN (insn)) != PARALLEL)
125 return NULL_RTX;
127 tmp = PATTERN (insn);
128 if (GET_CODE (XVECEXP (tmp, 0, 0)) != SET)
129 return NULL_RTX;
131 for (i = 1; i < XVECLEN (tmp, 0); ++i)
133 rtx this_rtx = XVECEXP (tmp, 0, i);
135 /* The special case is allowing a no-op set. */
136 if (GET_CODE (this_rtx) == SET
137 && SET_SRC (this_rtx) == SET_DEST (this_rtx))
139 else if (GET_CODE (this_rtx) != CLOBBER
140 && GET_CODE (this_rtx) != USE)
141 return NULL_RTX;
144 return XVECEXP (tmp, 0, 0);
147 /* Free the list of csa_reflist nodes. */
149 static void
150 free_csa_reflist (struct csa_reflist *reflist)
152 struct csa_reflist *next;
153 for (; reflist ; reflist = next)
155 next = reflist->next;
156 free (reflist);
160 /* Create a new csa_reflist node from the given stack reference.
161 It is already known that the reference is either a MEM satisfying the
162 predicate stack_memref_p or a REG representing the stack pointer. */
164 static struct csa_reflist *
165 record_one_stack_ref (rtx_insn *insn, rtx *ref, struct csa_reflist *next_reflist)
167 struct csa_reflist *ml;
169 ml = XNEW (struct csa_reflist);
171 if (REG_P (*ref) || XEXP (*ref, 0) == stack_pointer_rtx)
172 ml->sp_offset = 0;
173 else
174 ml->sp_offset = INTVAL (XEXP (XEXP (*ref, 0), 1));
176 ml->insn = insn;
177 ml->ref = ref;
178 ml->next = next_reflist;
180 return ml;
183 /* We only know how to adjust the CFA; no other frame-related changes
184 may appear in any insn to be deleted. */
186 static bool
187 no_unhandled_cfa (rtx_insn *insn)
189 if (!RTX_FRAME_RELATED_P (insn))
190 return true;
192 /* No CFA notes at all is a legacy interpretation like
193 FRAME_RELATED_EXPR, and is context sensitive within
194 the prologue state machine. We can't handle that here. */
195 bool has_cfa_adjust = false;
197 for (rtx link = REG_NOTES (insn); link; link = XEXP (link, 1))
198 switch (REG_NOTE_KIND (link))
200 default:
201 break;
202 case REG_CFA_ADJUST_CFA:
203 has_cfa_adjust = true;
204 break;
206 case REG_FRAME_RELATED_EXPR:
207 case REG_CFA_DEF_CFA:
208 case REG_CFA_OFFSET:
209 case REG_CFA_REGISTER:
210 case REG_CFA_EXPRESSION:
211 case REG_CFA_RESTORE:
212 case REG_CFA_SET_VDRAP:
213 case REG_CFA_WINDOW_SAVE:
214 case REG_CFA_FLUSH_QUEUE:
215 case REG_CFA_TOGGLE_RA_MANGLE:
216 return false;
219 return has_cfa_adjust;
222 /* Attempt to apply ADJUST to the stack adjusting insn INSN, as well
223 as each of the memories and stack references in REFLIST. Return true
224 on success. */
226 static bool
227 try_apply_stack_adjustment (rtx_insn *insn, struct csa_reflist *reflist,
228 HOST_WIDE_INT new_adjust, HOST_WIDE_INT delta,
229 bitmap live, rtx_insn *other_insn)
231 struct csa_reflist *ml;
232 rtx set;
233 bool remove_equal = false;
235 set = single_set_for_csa (insn);
236 if (MEM_P (SET_DEST (set)))
237 validate_change (insn, &SET_DEST (set),
238 replace_equiv_address (SET_DEST (set), stack_pointer_rtx),
240 else if (REG_P (SET_SRC (set)))
242 if (other_insn == NULL_RTX || live == NULL)
243 return false;
244 rtx other_set = single_set_for_csa (other_insn);
245 if (SET_DEST (other_set) != stack_pointer_rtx
246 || GET_CODE (SET_SRC (other_set)) != PLUS
247 || XEXP (SET_SRC (other_set), 0) != stack_pointer_rtx
248 || !CONST_INT_P (XEXP (SET_SRC (other_set), 1)))
249 return false;
250 if (PATTERN (other_insn) != other_set)
252 if (GET_CODE (PATTERN (other_insn)) != PARALLEL)
253 return false;
254 int i;
255 rtx p = PATTERN (other_insn);
256 for (i = 0; i < XVECLEN (p, 0); ++i)
258 rtx this_rtx = XVECEXP (p, 0, i);
259 if (this_rtx == other_set)
260 continue;
261 if (GET_CODE (this_rtx) != CLOBBER)
262 return false;
263 if (!REG_P (XEXP (this_rtx, 0))
264 || !HARD_REGISTER_P (XEXP (this_rtx, 0)))
265 return false;
266 unsigned int end_regno = END_REGNO (XEXP (this_rtx, 0));
267 for (unsigned int regno = REGNO (XEXP (this_rtx, 0));
268 regno < end_regno; ++regno)
269 if (bitmap_bit_p (live, regno))
270 return false;
273 validate_change (insn, &PATTERN (insn), copy_rtx (PATTERN (other_insn)),
275 set = single_set_for_csa (insn);
276 validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust),
278 remove_equal = true;
280 else
281 validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust), 1);
283 for (ml = reflist; ml ; ml = ml->next)
285 rtx new_addr = plus_constant (Pmode, stack_pointer_rtx,
286 ml->sp_offset - delta);
287 rtx new_val;
289 if (MEM_P (*ml->ref))
290 new_val = replace_equiv_address_nv (*ml->ref, new_addr);
291 else if (GET_MODE (*ml->ref) == GET_MODE (stack_pointer_rtx))
292 new_val = new_addr;
293 else
294 new_val = lowpart_subreg (GET_MODE (*ml->ref), new_addr,
295 GET_MODE (new_addr));
296 validate_change (ml->insn, ml->ref, new_val, 1);
299 if (apply_change_group ())
301 /* Succeeded. Update our knowledge of the stack references. */
302 for (ml = reflist; ml ; ml = ml->next)
303 ml->sp_offset -= delta;
305 if (remove_equal)
306 remove_reg_equal_equiv_notes (insn);
307 return true;
309 else
310 return false;
313 /* For non-debug insns, record all stack memory references in INSN
314 and return true if there were no other (unrecorded) references to the
315 stack pointer. For debug insns, record all stack references regardless
316 of context and unconditionally return true. */
318 static bool
319 record_stack_refs (rtx_insn *insn, struct csa_reflist **reflist)
321 subrtx_ptr_iterator::array_type array;
322 FOR_EACH_SUBRTX_PTR (iter, array, &PATTERN (insn), NONCONST)
324 rtx *loc = *iter;
325 rtx x = *loc;
326 switch (GET_CODE (x))
328 case MEM:
329 if (!reg_mentioned_p (stack_pointer_rtx, x))
330 iter.skip_subrtxes ();
331 /* We are not able to handle correctly all possible memrefs
332 containing stack pointer, so this check is necessary. */
333 else if (stack_memref_p (x))
335 *reflist = record_one_stack_ref (insn, loc, *reflist);
336 iter.skip_subrtxes ();
338 /* Try harder for DEBUG_INSNs, handle e.g.
339 (mem (mem (sp + 16) + 4). */
340 else if (!DEBUG_INSN_P (insn))
341 return false;
342 break;
344 case REG:
345 /* ??? We want be able to handle non-memory stack pointer
346 references later. For now just discard all insns referring to
347 stack pointer outside mem expressions. We would probably
348 want to teach validate_replace to simplify expressions first.
350 We can't just compare with STACK_POINTER_RTX because the
351 reference to the stack pointer might be in some other mode.
352 In particular, an explicit clobber in an asm statement will
353 result in a QImode clobber.
355 In DEBUG_INSNs, we want to replace all occurrences, otherwise
356 they will cause -fcompare-debug failures. */
357 if (REGNO (x) == STACK_POINTER_REGNUM)
359 if (!DEBUG_INSN_P (insn))
360 return false;
361 *reflist = record_one_stack_ref (insn, loc, *reflist);
363 break;
365 default:
366 break;
369 return true;
372 /* If INSN has a REG_ARGS_SIZE note, move it to LAST.
373 AFTER is true iff LAST follows INSN in the instruction stream. */
375 static void
376 maybe_move_args_size_note (rtx_insn *last, rtx_insn *insn, bool after)
378 rtx note, last_note;
380 note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
381 if (note == NULL)
382 return;
384 last_note = find_reg_note (last, REG_ARGS_SIZE, NULL_RTX);
385 if (last_note)
387 /* The ARGS_SIZE notes are *not* cumulative. They represent an
388 absolute value, and the "most recent" note wins. */
389 if (!after)
390 XEXP (last_note, 0) = XEXP (note, 0);
392 else
393 add_reg_note (last, REG_ARGS_SIZE, XEXP (note, 0));
396 /* Merge any REG_CFA_ADJUST_CFA note from SRC into DST.
397 AFTER is true iff DST follows SRC in the instruction stream. */
399 static void
400 maybe_merge_cfa_adjust (rtx_insn *dst, rtx_insn *src, bool after)
402 rtx snote = NULL, dnote = NULL;
403 rtx sexp, dexp;
404 rtx exp1, exp2;
406 if (RTX_FRAME_RELATED_P (src))
407 snote = find_reg_note (src, REG_CFA_ADJUST_CFA, NULL_RTX);
408 if (snote == NULL)
409 return;
410 sexp = XEXP (snote, 0);
412 if (RTX_FRAME_RELATED_P (dst))
413 dnote = find_reg_note (dst, REG_CFA_ADJUST_CFA, NULL_RTX);
414 if (dnote == NULL)
416 add_reg_note (dst, REG_CFA_ADJUST_CFA, sexp);
417 return;
419 dexp = XEXP (dnote, 0);
421 gcc_assert (GET_CODE (sexp) == SET);
422 gcc_assert (GET_CODE (dexp) == SET);
424 if (after)
425 exp1 = dexp, exp2 = sexp;
426 else
427 exp1 = sexp, exp2 = dexp;
429 SET_SRC (exp1) = simplify_replace_rtx (SET_SRC (exp1), SET_DEST (exp2),
430 SET_SRC (exp2));
431 XEXP (dnote, 0) = exp1;
434 /* Return the next (or previous) active insn within BB. */
436 static rtx_insn *
437 prev_active_insn_bb (basic_block bb, rtx_insn *insn)
439 for (insn = PREV_INSN (insn);
440 insn != PREV_INSN (BB_HEAD (bb));
441 insn = PREV_INSN (insn))
442 if (active_insn_p (insn))
443 return insn;
444 return NULL;
447 static rtx_insn *
448 next_active_insn_bb (basic_block bb, rtx_insn *insn)
450 for (insn = NEXT_INSN (insn);
451 insn != NEXT_INSN (BB_END (bb));
452 insn = NEXT_INSN (insn))
453 if (active_insn_p (insn))
454 return insn;
455 return NULL;
458 /* If INSN has a REG_ARGS_SIZE note, if possible move it to PREV. Otherwise
459 search for a nearby candidate within BB where we can stick the note. */
461 static void
462 force_move_args_size_note (basic_block bb, rtx_insn *prev, rtx_insn *insn)
464 rtx note;
465 rtx_insn *test, *next_candidate, *prev_candidate;
467 /* If PREV exists, tail-call to the logic in the other function. */
468 if (prev)
470 maybe_move_args_size_note (prev, insn, false);
471 return;
474 /* First, make sure there's anything that needs doing. */
475 note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
476 if (note == NULL)
477 return;
479 /* We need to find a spot between the previous and next exception points
480 where we can place the note and "properly" deallocate the arguments. */
481 next_candidate = prev_candidate = NULL;
483 /* It is often the case that we have insns in the order:
484 call
485 add sp (previous deallocation)
486 sub sp (align for next arglist)
487 push arg
488 and the add/sub cancel. Therefore we begin by searching forward. */
490 test = insn;
491 while ((test = next_active_insn_bb (bb, test)) != NULL)
493 /* Found an existing note: nothing to do. */
494 if (find_reg_note (test, REG_ARGS_SIZE, NULL_RTX))
495 return;
496 /* Found something that affects unwinding. Stop searching. */
497 if (CALL_P (test) || !insn_nothrow_p (test))
498 break;
499 if (next_candidate == NULL)
500 next_candidate = test;
503 test = insn;
504 while ((test = prev_active_insn_bb (bb, test)) != NULL)
506 rtx tnote;
507 /* Found a place that seems logical to adjust the stack. */
508 tnote = find_reg_note (test, REG_ARGS_SIZE, NULL_RTX);
509 if (tnote)
511 XEXP (tnote, 0) = XEXP (note, 0);
512 return;
514 if (prev_candidate == NULL)
515 prev_candidate = test;
516 /* Found something that affects unwinding. Stop searching. */
517 if (CALL_P (test) || !insn_nothrow_p (test))
518 break;
521 if (prev_candidate)
522 test = prev_candidate;
523 else if (next_candidate)
524 test = next_candidate;
525 else
527 /* ??? We *must* have a place, lest we ICE on the lost adjustment.
528 Options are: dummy clobber insn, nop, or prevent the removal of
529 the sp += 0 insn. */
530 /* TODO: Find another way to indicate to the dwarf2 code that we
531 have not in fact lost an adjustment. */
532 test = emit_insn_before (gen_rtx_CLOBBER (VOIDmode, const0_rtx), insn);
534 add_reg_note (test, REG_ARGS_SIZE, XEXP (note, 0));
537 /* Subroutine of combine_stack_adjustments, called for each basic block. */
539 static void
540 combine_stack_adjustments_for_block (basic_block bb, bitmap live)
542 HOST_WIDE_INT last_sp_adjust = 0;
543 rtx_insn *last_sp_set = NULL;
544 rtx_insn *last2_sp_set = NULL;
545 bitmap last_sp_live = NULL;
546 struct csa_reflist *reflist = NULL;
547 bitmap copy = NULL;
548 rtx_insn *insn, *next;
549 rtx set;
550 bool end_of_block = false;
552 bitmap_copy (live, DF_LR_IN (bb));
553 df_simulate_initialize_forwards (bb, live);
555 for (insn = BB_HEAD (bb); !end_of_block ; insn = next)
557 end_of_block = insn == BB_END (bb);
558 next = NEXT_INSN (insn);
560 if (! INSN_P (insn))
561 continue;
563 set = single_set_for_csa (insn);
564 if (set && find_reg_note (insn, REG_STACK_CHECK, NULL_RTX))
565 set = NULL_RTX;
566 if (set)
568 rtx dest = SET_DEST (set);
569 rtx src = SET_SRC (set);
570 HOST_WIDE_INT this_adjust = 0;
572 /* Find constant additions to the stack pointer. */
573 if (dest == stack_pointer_rtx
574 && GET_CODE (src) == PLUS
575 && XEXP (src, 0) == stack_pointer_rtx
576 && CONST_INT_P (XEXP (src, 1)))
577 this_adjust = INTVAL (XEXP (src, 1));
578 /* Or such additions turned by postreload into a store of
579 equivalent register. */
580 else if (dest == stack_pointer_rtx
581 && REG_P (src)
582 && REGNO (src) != STACK_POINTER_REGNUM)
583 if (rtx equal = find_reg_note (insn, REG_EQUAL, NULL_RTX))
584 if (GET_CODE (XEXP (equal, 0)) == PLUS
585 && XEXP (XEXP (equal, 0), 0) == stack_pointer_rtx
586 && CONST_INT_P (XEXP (XEXP (equal, 0), 1)))
587 this_adjust = INTVAL (XEXP (XEXP (equal, 0), 1));
589 if (this_adjust)
591 /* If we've not seen an adjustment previously, record
592 it now and continue. */
593 if (! last_sp_set)
595 last_sp_set = insn;
596 last_sp_adjust = this_adjust;
597 if (REG_P (src))
599 if (copy == NULL)
600 copy = BITMAP_ALLOC (&reg_obstack);
601 last_sp_live = copy;
602 bitmap_copy (last_sp_live, live);
604 else
605 last_sp_live = NULL;
606 df_simulate_one_insn_forwards (bb, insn, live);
607 continue;
610 /* If not all recorded refs can be adjusted, or the
611 adjustment is now too large for a constant addition,
612 we cannot merge the two stack adjustments.
614 Also we need to be careful to not move stack pointer
615 such that we create stack accesses outside the allocated
616 area. We can combine an allocation into the first insn,
617 or a deallocation into the second insn. We cannot
618 combine an allocation followed by a deallocation.
620 The only somewhat frequent occurrence of the later is when
621 a function allocates a stack frame but does not use it.
622 For this case, we would need to analyze rtl stream to be
623 sure that allocated area is really unused. This means not
624 only checking the memory references, but also all registers
625 or global memory references possibly containing a stack
626 frame address.
628 Perhaps the best way to address this problem is to teach
629 gcc not to allocate stack for objects never used. */
631 /* Combine an allocation into the first instruction. */
632 if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0)
634 if (no_unhandled_cfa (insn)
635 && try_apply_stack_adjustment (last_sp_set, reflist,
636 last_sp_adjust
637 + this_adjust,
638 this_adjust,
639 last_sp_live,
640 insn))
642 /* It worked! */
643 maybe_move_args_size_note (last_sp_set, insn, false);
644 maybe_merge_cfa_adjust (last_sp_set, insn, false);
645 delete_insn (insn);
646 last_sp_adjust += this_adjust;
647 last_sp_live = NULL;
648 continue;
652 /* Otherwise we have a deallocation. Do not combine with
653 a previous allocation. Combine into the second insn. */
654 else if (STACK_GROWS_DOWNWARD
655 ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
657 if (no_unhandled_cfa (last_sp_set)
658 && !REG_P (src)
659 && try_apply_stack_adjustment (insn, reflist,
660 last_sp_adjust
661 + this_adjust,
662 -last_sp_adjust,
663 NULL, NULL))
665 /* It worked! */
666 maybe_move_args_size_note (insn, last_sp_set, true);
667 maybe_merge_cfa_adjust (insn, last_sp_set, true);
668 delete_insn (last_sp_set);
669 last_sp_set = insn;
670 last_sp_adjust += this_adjust;
671 last_sp_live = NULL;
672 free_csa_reflist (reflist);
673 reflist = NULL;
674 df_simulate_one_insn_forwards (bb, insn, live);
675 continue;
679 /* Combination failed. Restart processing from here. If
680 deallocation+allocation conspired to cancel, we can
681 delete the old deallocation insn. */
682 if (last_sp_set)
684 if (last_sp_adjust == 0 && no_unhandled_cfa (last_sp_set))
686 maybe_move_args_size_note (insn, last_sp_set, true);
687 maybe_merge_cfa_adjust (insn, last_sp_set, true);
688 delete_insn (last_sp_set);
690 else
691 last2_sp_set = last_sp_set;
693 free_csa_reflist (reflist);
694 reflist = NULL;
695 last_sp_set = insn;
696 last_sp_adjust = this_adjust;
697 if (REG_P (src))
699 if (copy == NULL)
700 copy = BITMAP_ALLOC (&reg_obstack);
701 last_sp_live = copy;
702 bitmap_copy (last_sp_live, live);
704 else
705 last_sp_live = NULL;
706 df_simulate_one_insn_forwards (bb, insn, live);
707 continue;
710 /* Find a store with pre-(dec|inc)rement or pre-modify of exactly
711 the previous adjustment and turn it into a simple store. This
712 is equivalent to anticipating the stack adjustment so this must
713 be an allocation. */
714 if (MEM_P (dest)
715 && ((STACK_GROWS_DOWNWARD
716 ? (GET_CODE (XEXP (dest, 0)) == PRE_DEC
717 && known_eq (last_sp_adjust,
718 GET_MODE_SIZE (GET_MODE (dest))))
719 : (GET_CODE (XEXP (dest, 0)) == PRE_INC
720 && known_eq (-last_sp_adjust,
721 GET_MODE_SIZE (GET_MODE (dest)))))
722 || ((STACK_GROWS_DOWNWARD
723 ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
724 && GET_CODE (XEXP (dest, 0)) == PRE_MODIFY
725 && GET_CODE (XEXP (XEXP (dest, 0), 1)) == PLUS
726 && XEXP (XEXP (XEXP (dest, 0), 1), 0)
727 == stack_pointer_rtx
728 && GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
729 == CONST_INT
730 && INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1))
731 == -last_sp_adjust))
732 && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
733 && !reg_mentioned_p (stack_pointer_rtx, src)
734 && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
735 && try_apply_stack_adjustment (insn, reflist, 0,
736 -last_sp_adjust,
737 NULL, NULL))
739 if (last2_sp_set)
740 maybe_move_args_size_note (last2_sp_set, last_sp_set, false);
741 else
742 maybe_move_args_size_note (insn, last_sp_set, true);
743 delete_insn (last_sp_set);
744 free_csa_reflist (reflist);
745 reflist = NULL;
746 last_sp_set = NULL;
747 last_sp_adjust = 0;
748 last_sp_live = NULL;
749 df_simulate_one_insn_forwards (bb, insn, live);
750 continue;
754 if (!CALL_P (insn) && last_sp_set && record_stack_refs (insn, &reflist))
756 df_simulate_one_insn_forwards (bb, insn, live);
757 continue;
760 /* Otherwise, we were not able to process the instruction.
761 Do not continue collecting data across such a one. */
762 if (last_sp_set
763 && (CALL_P (insn)
764 || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
766 if (last_sp_set && last_sp_adjust == 0)
768 force_move_args_size_note (bb, last2_sp_set, last_sp_set);
769 delete_insn (last_sp_set);
771 free_csa_reflist (reflist);
772 reflist = NULL;
773 last2_sp_set = NULL;
774 last_sp_set = NULL;
775 last_sp_adjust = 0;
776 last_sp_live = NULL;
779 df_simulate_one_insn_forwards (bb, insn, live);
782 if (last_sp_set && last_sp_adjust == 0)
784 force_move_args_size_note (bb, last2_sp_set, last_sp_set);
785 delete_insn (last_sp_set);
788 if (reflist)
789 free_csa_reflist (reflist);
790 if (copy)
791 BITMAP_FREE (copy);
794 static void
795 rest_of_handle_stack_adjustments (void)
797 df_note_add_problem ();
798 df_analyze ();
799 combine_stack_adjustments ();
802 namespace {
804 const pass_data pass_data_stack_adjustments =
806 RTL_PASS, /* type */
807 "csa", /* name */
808 OPTGROUP_NONE, /* optinfo_flags */
809 TV_COMBINE_STACK_ADJUST, /* tv_id */
810 0, /* properties_required */
811 0, /* properties_provided */
812 0, /* properties_destroyed */
813 0, /* todo_flags_start */
814 TODO_df_finish, /* todo_flags_finish */
817 class pass_stack_adjustments : public rtl_opt_pass
819 public:
820 pass_stack_adjustments (gcc::context *ctxt)
821 : rtl_opt_pass (pass_data_stack_adjustments, ctxt)
824 /* opt_pass methods: */
825 bool gate (function *) final override;
826 unsigned int execute (function *) final override
828 rest_of_handle_stack_adjustments ();
829 return 0;
832 }; // class pass_stack_adjustments
834 bool
835 pass_stack_adjustments::gate (function *)
837 /* This is kind of a heuristic. We need to run combine_stack_adjustments
838 even for machines with possibly nonzero TARGET_RETURN_POPS_ARGS
839 and ACCUMULATE_OUTGOING_ARGS. We expect that only ports having
840 push instructions will have popping returns. */
841 #ifndef PUSH_ROUNDING
842 if (ACCUMULATE_OUTGOING_ARGS)
843 return false;
844 #endif
845 return flag_combine_stack_adjustments;
848 } // anon namespace
850 rtl_opt_pass *
851 make_pass_stack_adjustments (gcc::context *ctxt)
853 return new pass_stack_adjustments (ctxt);