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
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
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
43 #include "coretypes.h"
47 #include "insn-config.h"
52 #include "tree-pass.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. */
62 HOST_WIDE_INT sp_offset
;
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
,
76 static void combine_stack_adjustments_for_block (basic_block
, bitmap
);
79 /* Main entry point for stack adjustment combination. */
82 combine_stack_adjustments (void)
85 bitmap live
= BITMAP_ALLOC (®_obstack
);
87 FOR_EACH_BB_FN (bb
, cfun
)
88 combine_stack_adjustments_for_block (bb
, live
);
93 /* Recognize a MEM of the form (sp) or (plus sp const). */
96 stack_memref_p (rtx x
)
102 if (x
== stack_pointer_rtx
)
104 if (GET_CODE (x
) == PLUS
105 && XEXP (x
, 0) == stack_pointer_rtx
106 && CONST_INT_P (XEXP (x
, 1)))
112 /* Recognize either normal single_set or the hack in i386.md for
113 tying fp and sp adjustments. */
116 single_set_for_csa (rtx_insn
*insn
)
119 rtx tmp
= single_set (insn
);
123 if (!NONJUMP_INSN_P (insn
)
124 || GET_CODE (PATTERN (insn
)) != PARALLEL
)
127 tmp
= PATTERN (insn
);
128 if (GET_CODE (XVECEXP (tmp
, 0, 0)) != SET
)
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
)
144 return XVECEXP (tmp
, 0, 0);
147 /* Free the list of csa_reflist nodes. */
150 free_csa_reflist (struct csa_reflist
*reflist
)
152 struct csa_reflist
*next
;
153 for (; reflist
; reflist
= next
)
155 next
= reflist
->next
;
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
)
174 ml
->sp_offset
= INTVAL (XEXP (XEXP (*ref
, 0), 1));
178 ml
->next
= next_reflist
;
183 /* We only know how to adjust the CFA; no other frame-related changes
184 may appear in any insn to be deleted. */
187 no_unhandled_cfa (rtx_insn
*insn
)
189 if (!RTX_FRAME_RELATED_P (insn
))
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
))
202 case REG_CFA_ADJUST_CFA
:
203 has_cfa_adjust
= true;
206 case REG_FRAME_RELATED_EXPR
:
207 case REG_CFA_DEF_CFA
:
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
:
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
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
;
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
)
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)))
250 if (PATTERN (other_insn
) != other_set
)
252 if (GET_CODE (PATTERN (other_insn
)) != PARALLEL
)
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
)
261 if (GET_CODE (this_rtx
) != CLOBBER
)
263 if (!REG_P (XEXP (this_rtx
, 0))
264 || !HARD_REGISTER_P (XEXP (this_rtx
, 0)))
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
))
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
),
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
);
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
))
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
;
306 remove_reg_equal_equiv_notes (insn
);
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. */
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
)
326 switch (GET_CODE (x
))
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
))
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
))
361 *reflist
= record_one_stack_ref (insn
, loc
, *reflist
);
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. */
376 maybe_move_args_size_note (rtx_insn
*last
, rtx_insn
*insn
, bool after
)
380 note
= find_reg_note (insn
, REG_ARGS_SIZE
, NULL_RTX
);
384 last_note
= find_reg_note (last
, REG_ARGS_SIZE
, NULL_RTX
);
387 /* The ARGS_SIZE notes are *not* cumulative. They represent an
388 absolute value, and the "most recent" note wins. */
390 XEXP (last_note
, 0) = XEXP (note
, 0);
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. */
400 maybe_merge_cfa_adjust (rtx_insn
*dst
, rtx_insn
*src
, bool after
)
402 rtx snote
= NULL
, dnote
= NULL
;
406 if (RTX_FRAME_RELATED_P (src
))
407 snote
= find_reg_note (src
, REG_CFA_ADJUST_CFA
, NULL_RTX
);
410 sexp
= XEXP (snote
, 0);
412 if (RTX_FRAME_RELATED_P (dst
))
413 dnote
= find_reg_note (dst
, REG_CFA_ADJUST_CFA
, NULL_RTX
);
416 add_reg_note (dst
, REG_CFA_ADJUST_CFA
, sexp
);
419 dexp
= XEXP (dnote
, 0);
421 gcc_assert (GET_CODE (sexp
) == SET
);
422 gcc_assert (GET_CODE (dexp
) == SET
);
425 exp1
= dexp
, exp2
= sexp
;
427 exp1
= sexp
, exp2
= dexp
;
429 SET_SRC (exp1
) = simplify_replace_rtx (SET_SRC (exp1
), SET_DEST (exp2
),
431 XEXP (dnote
, 0) = exp1
;
434 /* Return the next (or previous) active insn within BB. */
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
))
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
))
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. */
462 force_move_args_size_note (basic_block bb
, rtx_insn
*prev
, rtx_insn
*insn
)
465 rtx_insn
*test
, *next_candidate
, *prev_candidate
;
467 /* If PREV exists, tail-call to the logic in the other function. */
470 maybe_move_args_size_note (prev
, insn
, false);
474 /* First, make sure there's anything that needs doing. */
475 note
= find_reg_note (insn
, REG_ARGS_SIZE
, NULL_RTX
);
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:
485 add sp (previous deallocation)
486 sub sp (align for next arglist)
488 and the add/sub cancel. Therefore we begin by searching forward. */
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
))
496 /* Found something that affects unwinding. Stop searching. */
497 if (CALL_P (test
) || !insn_nothrow_p (test
))
499 if (next_candidate
== NULL
)
500 next_candidate
= test
;
504 while ((test
= prev_active_insn_bb (bb
, test
)) != NULL
)
507 /* Found a place that seems logical to adjust the stack. */
508 tnote
= find_reg_note (test
, REG_ARGS_SIZE
, NULL_RTX
);
511 XEXP (tnote
, 0) = XEXP (note
, 0);
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
))
522 test
= prev_candidate
;
523 else if (next_candidate
)
524 test
= next_candidate
;
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
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. */
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
;
548 rtx_insn
*insn
, *next
;
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
);
563 set
= single_set_for_csa (insn
);
564 if (set
&& find_reg_note (insn
, REG_STACK_CHECK
, NULL_RTX
))
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
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));
591 /* If we've not seen an adjustment previously, record
592 it now and continue. */
596 last_sp_adjust
= this_adjust
;
600 copy
= BITMAP_ALLOC (®_obstack
);
602 bitmap_copy (last_sp_live
, live
);
606 df_simulate_one_insn_forwards (bb
, insn
, live
);
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
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
,
643 maybe_move_args_size_note (last_sp_set
, insn
, false);
644 maybe_merge_cfa_adjust (last_sp_set
, insn
, false);
646 last_sp_adjust
+= this_adjust
;
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
)
659 && try_apply_stack_adjustment (insn
, reflist
,
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
);
670 last_sp_adjust
+= this_adjust
;
672 free_csa_reflist (reflist
);
674 df_simulate_one_insn_forwards (bb
, insn
, live
);
679 /* Combination failed. Restart processing from here. If
680 deallocation+allocation conspired to cancel, we can
681 delete the old deallocation insn. */
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
);
691 last2_sp_set
= last_sp_set
;
693 free_csa_reflist (reflist
);
696 last_sp_adjust
= this_adjust
;
700 copy
= BITMAP_ALLOC (®_obstack
);
702 bitmap_copy (last_sp_live
, live
);
706 df_simulate_one_insn_forwards (bb
, insn
, live
);
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
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)
728 && GET_CODE (XEXP (XEXP (XEXP (dest
, 0), 1), 1))
730 && INTVAL (XEXP (XEXP (XEXP (dest
, 0), 1), 1))
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,
740 maybe_move_args_size_note (last2_sp_set
, last_sp_set
, false);
742 maybe_move_args_size_note (insn
, last_sp_set
, true);
743 delete_insn (last_sp_set
);
744 free_csa_reflist (reflist
);
749 df_simulate_one_insn_forwards (bb
, insn
, live
);
754 if (!CALL_P (insn
) && last_sp_set
&& record_stack_refs (insn
, &reflist
))
756 df_simulate_one_insn_forwards (bb
, insn
, live
);
760 /* Otherwise, we were not able to process the instruction.
761 Do not continue collecting data across such a one. */
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
);
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
);
789 free_csa_reflist (reflist
);
795 rest_of_handle_stack_adjustments (void)
797 df_note_add_problem ();
799 combine_stack_adjustments ();
804 const pass_data pass_data_stack_adjustments
=
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
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 ();
832 }; // class pass_stack_adjustments
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
)
845 return flag_combine_stack_adjustments
;
851 make_pass_stack_adjustments (gcc::context
*ctxt
)
853 return new pass_stack_adjustments (ctxt
);