123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789 |
- /* Combine stack adjustments.
- Copyright (C) 1987-2015 Free Software Foundation, Inc.
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3, or (at your option) any later
- version.
- GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- /* Track stack adjustments and stack memory references. Attempt to
- reduce the number of stack adjustments by back-propagating across
- the memory references.
- This is intended primarily for use with targets that do not define
- ACCUMULATE_OUTGOING_ARGS. It is of significantly more value to
- targets that define PREFERRED_STACK_BOUNDARY more aligned than
- STACK_BOUNDARY (e.g. x86), or if not all registers can be pushed
- (e.g. x86 fp regs) which would ordinarily have to be implemented
- as a sub/mov pair due to restrictions in calls.c.
- Propagation stops when any of the insns that need adjusting are
- (a) no longer valid because we've exceeded their range, (b) a
- non-trivial push instruction, or (c) a call instruction.
- Restriction B is based on the assumption that push instructions
- are smaller or faster. If a port really wants to remove all
- pushes, it should have defined ACCUMULATE_OUTGOING_ARGS. The
- one exception that is made is for an add immediately followed
- by a push. */
- #include "config.h"
- #include "system.h"
- #include "coretypes.h"
- #include "tm.h"
- #include "rtl.h"
- #include "tm_p.h"
- #include "insn-config.h"
- #include "recog.h"
- #include "regs.h"
- #include "hard-reg-set.h"
- #include "flags.h"
- #include "hashtab.h"
- #include "hash-set.h"
- #include "vec.h"
- #include "machmode.h"
- #include "input.h"
- #include "function.h"
- #include "symtab.h"
- #include "statistics.h"
- #include "double-int.h"
- #include "real.h"
- #include "fixed-value.h"
- #include "alias.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "tree.h"
- #include "expmed.h"
- #include "dojump.h"
- #include "explow.h"
- #include "calls.h"
- #include "emit-rtl.h"
- #include "varasm.h"
- #include "stmt.h"
- #include "expr.h"
- #include "predict.h"
- #include "dominance.h"
- #include "cfg.h"
- #include "cfgrtl.h"
- #include "basic-block.h"
- #include "df.h"
- #include "except.h"
- #include "reload.h"
- #include "tree-pass.h"
- #include "rtl-iter.h"
- /* Turn STACK_GROWS_DOWNWARD into a boolean. */
- #ifdef STACK_GROWS_DOWNWARD
- #undef STACK_GROWS_DOWNWARD
- #define STACK_GROWS_DOWNWARD 1
- #else
- #define STACK_GROWS_DOWNWARD 0
- #endif
- /* This structure records two kinds of stack references between stack
- adjusting instructions: stack references in memory addresses for
- regular insns and all stack references for debug insns. */
- struct csa_reflist
- {
- HOST_WIDE_INT sp_offset;
- rtx_insn *insn;
- rtx *ref;
- struct csa_reflist *next;
- };
- static int stack_memref_p (rtx);
- static rtx single_set_for_csa (rtx_insn *);
- static void free_csa_reflist (struct csa_reflist *);
- static struct csa_reflist *record_one_stack_ref (rtx_insn *, rtx *,
- struct csa_reflist *);
- static int try_apply_stack_adjustment (rtx_insn *, struct csa_reflist *,
- HOST_WIDE_INT, HOST_WIDE_INT);
- static void combine_stack_adjustments_for_block (basic_block);
- /* Main entry point for stack adjustment combination. */
- static void
- combine_stack_adjustments (void)
- {
- basic_block bb;
- FOR_EACH_BB_FN (bb, cfun)
- combine_stack_adjustments_for_block (bb);
- }
- /* Recognize a MEM of the form (sp) or (plus sp const). */
- static int
- stack_memref_p (rtx x)
- {
- if (!MEM_P (x))
- return 0;
- x = XEXP (x, 0);
- if (x == stack_pointer_rtx)
- return 1;
- if (GET_CODE (x) == PLUS
- && XEXP (x, 0) == stack_pointer_rtx
- && CONST_INT_P (XEXP (x, 1)))
- return 1;
- return 0;
- }
- /* Recognize either normal single_set or the hack in i386.md for
- tying fp and sp adjustments. */
- static rtx
- single_set_for_csa (rtx_insn *insn)
- {
- int i;
- rtx tmp = single_set (insn);
- if (tmp)
- return tmp;
- if (!NONJUMP_INSN_P (insn)
- || GET_CODE (PATTERN (insn)) != PARALLEL)
- return NULL_RTX;
- tmp = PATTERN (insn);
- if (GET_CODE (XVECEXP (tmp, 0, 0)) != SET)
- return NULL_RTX;
- for (i = 1; i < XVECLEN (tmp, 0); ++i)
- {
- rtx this_rtx = XVECEXP (tmp, 0, i);
- /* The special case is allowing a no-op set. */
- if (GET_CODE (this_rtx) == SET
- && SET_SRC (this_rtx) == SET_DEST (this_rtx))
- ;
- else if (GET_CODE (this_rtx) != CLOBBER
- && GET_CODE (this_rtx) != USE)
- return NULL_RTX;
- }
- return XVECEXP (tmp, 0, 0);
- }
- /* Free the list of csa_reflist nodes. */
- static void
- free_csa_reflist (struct csa_reflist *reflist)
- {
- struct csa_reflist *next;
- for (; reflist ; reflist = next)
- {
- next = reflist->next;
- free (reflist);
- }
- }
- /* Create a new csa_reflist node from the given stack reference.
- It is already known that the reference is either a MEM satisfying the
- predicate stack_memref_p or a REG representing the stack pointer. */
- static struct csa_reflist *
- record_one_stack_ref (rtx_insn *insn, rtx *ref, struct csa_reflist *next_reflist)
- {
- struct csa_reflist *ml;
- ml = XNEW (struct csa_reflist);
- if (REG_P (*ref) || XEXP (*ref, 0) == stack_pointer_rtx)
- ml->sp_offset = 0;
- else
- ml->sp_offset = INTVAL (XEXP (XEXP (*ref, 0), 1));
- ml->insn = insn;
- ml->ref = ref;
- ml->next = next_reflist;
- return ml;
- }
- /* We only know how to adjust the CFA; no other frame-related changes
- may appear in any insn to be deleted. */
- static bool
- no_unhandled_cfa (rtx_insn *insn)
- {
- if (!RTX_FRAME_RELATED_P (insn))
- return true;
- /* No CFA notes at all is a legacy interpretation like
- FRAME_RELATED_EXPR, and is context sensitive within
- the prologue state machine. We can't handle that here. */
- bool has_cfa_adjust = false;
- for (rtx link = REG_NOTES (insn); link; link = XEXP (link, 1))
- switch (REG_NOTE_KIND (link))
- {
- default:
- break;
- case REG_CFA_ADJUST_CFA:
- has_cfa_adjust = true;
- break;
- case REG_FRAME_RELATED_EXPR:
- case REG_CFA_DEF_CFA:
- case REG_CFA_OFFSET:
- case REG_CFA_REGISTER:
- case REG_CFA_EXPRESSION:
- case REG_CFA_RESTORE:
- case REG_CFA_SET_VDRAP:
- case REG_CFA_WINDOW_SAVE:
- case REG_CFA_FLUSH_QUEUE:
- return false;
- }
- return has_cfa_adjust;
- }
- /* Attempt to apply ADJUST to the stack adjusting insn INSN, as well
- as each of the memories and stack references in REFLIST. Return true
- on success. */
- static int
- try_apply_stack_adjustment (rtx_insn *insn, struct csa_reflist *reflist,
- HOST_WIDE_INT new_adjust, HOST_WIDE_INT delta)
- {
- struct csa_reflist *ml;
- rtx set;
- set = single_set_for_csa (insn);
- if (MEM_P (SET_DEST (set)))
- validate_change (insn, &SET_DEST (set),
- replace_equiv_address (SET_DEST (set), stack_pointer_rtx),
- 1);
- else
- validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust), 1);
- for (ml = reflist; ml ; ml = ml->next)
- {
- rtx new_addr = plus_constant (Pmode, stack_pointer_rtx,
- ml->sp_offset - delta);
- rtx new_val;
- if (MEM_P (*ml->ref))
- new_val = replace_equiv_address_nv (*ml->ref, new_addr);
- else if (GET_MODE (*ml->ref) == GET_MODE (stack_pointer_rtx))
- new_val = new_addr;
- else
- new_val = lowpart_subreg (GET_MODE (*ml->ref), new_addr,
- GET_MODE (new_addr));
- validate_change (ml->insn, ml->ref, new_val, 1);
- }
- if (apply_change_group ())
- {
- /* Succeeded. Update our knowledge of the stack references. */
- for (ml = reflist; ml ; ml = ml->next)
- ml->sp_offset -= delta;
- return 1;
- }
- else
- return 0;
- }
- /* For non-debug insns, record all stack memory references in INSN
- and return true if there were no other (unrecorded) references to the
- stack pointer. For debug insns, record all stack references regardless
- of context and unconditionally return true. */
- static bool
- record_stack_refs (rtx_insn *insn, struct csa_reflist **reflist)
- {
- subrtx_ptr_iterator::array_type array;
- FOR_EACH_SUBRTX_PTR (iter, array, &PATTERN (insn), NONCONST)
- {
- rtx *loc = *iter;
- rtx x = *loc;
- switch (GET_CODE (x))
- {
- case MEM:
- if (!reg_mentioned_p (stack_pointer_rtx, x))
- iter.skip_subrtxes ();
- /* We are not able to handle correctly all possible memrefs
- containing stack pointer, so this check is necessary. */
- else if (stack_memref_p (x))
- {
- *reflist = record_one_stack_ref (insn, loc, *reflist);
- iter.skip_subrtxes ();
- }
- /* Try harder for DEBUG_INSNs, handle e.g.
- (mem (mem (sp + 16) + 4). */
- else if (!DEBUG_INSN_P (insn))
- return false;
- break;
- case REG:
- /* ??? We want be able to handle non-memory stack pointer
- references later. For now just discard all insns referring to
- stack pointer outside mem expressions. We would probably
- want to teach validate_replace to simplify expressions first.
- We can't just compare with STACK_POINTER_RTX because the
- reference to the stack pointer might be in some other mode.
- In particular, an explicit clobber in an asm statement will
- result in a QImode clobber.
- In DEBUG_INSNs, we want to replace all occurrences, otherwise
- they will cause -fcompare-debug failures. */
- if (REGNO (x) == STACK_POINTER_REGNUM)
- {
- if (!DEBUG_INSN_P (insn))
- return false;
- *reflist = record_one_stack_ref (insn, loc, *reflist);
- }
- break;
- default:
- break;
- }
- }
- return true;
- }
- /* If INSN has a REG_ARGS_SIZE note, move it to LAST.
- AFTER is true iff LAST follows INSN in the instruction stream. */
- static void
- maybe_move_args_size_note (rtx_insn *last, rtx_insn *insn, bool after)
- {
- rtx note, last_note;
- note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
- if (note == NULL)
- return;
- last_note = find_reg_note (last, REG_ARGS_SIZE, NULL_RTX);
- if (last_note)
- {
- /* The ARGS_SIZE notes are *not* cumulative. They represent an
- absolute value, and the "most recent" note wins. */
- if (!after)
- XEXP (last_note, 0) = XEXP (note, 0);
- }
- else
- add_reg_note (last, REG_ARGS_SIZE, XEXP (note, 0));
- }
- /* Merge any REG_CFA_ADJUST_CFA note from SRC into DST.
- AFTER is true iff DST follows SRC in the instruction stream. */
- static void
- maybe_merge_cfa_adjust (rtx_insn *dst, rtx_insn *src, bool after)
- {
- rtx snote = NULL, dnote = NULL;
- rtx sexp, dexp;
- rtx exp1, exp2;
- if (RTX_FRAME_RELATED_P (src))
- snote = find_reg_note (src, REG_CFA_ADJUST_CFA, NULL_RTX);
- if (snote == NULL)
- return;
- sexp = XEXP (snote, 0);
- if (RTX_FRAME_RELATED_P (dst))
- dnote = find_reg_note (dst, REG_CFA_ADJUST_CFA, NULL_RTX);
- if (dnote == NULL)
- {
- add_reg_note (dst, REG_CFA_ADJUST_CFA, sexp);
- return;
- }
- dexp = XEXP (dnote, 0);
- gcc_assert (GET_CODE (sexp) == SET);
- gcc_assert (GET_CODE (dexp) == SET);
- if (after)
- exp1 = dexp, exp2 = sexp;
- else
- exp1 = sexp, exp2 = dexp;
- SET_SRC (exp1) = simplify_replace_rtx (SET_SRC (exp1), SET_DEST (exp2),
- SET_SRC (exp2));
- XEXP (dnote, 0) = exp1;
- }
- /* Return the next (or previous) active insn within BB. */
- static rtx_insn *
- prev_active_insn_bb (basic_block bb, rtx_insn *insn)
- {
- for (insn = PREV_INSN (insn);
- insn != PREV_INSN (BB_HEAD (bb));
- insn = PREV_INSN (insn))
- if (active_insn_p (insn))
- return insn;
- return NULL;
- }
- static rtx_insn *
- next_active_insn_bb (basic_block bb, rtx_insn *insn)
- {
- for (insn = NEXT_INSN (insn);
- insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
- if (active_insn_p (insn))
- return insn;
- return NULL;
- }
- /* If INSN has a REG_ARGS_SIZE note, if possible move it to PREV. Otherwise
- search for a nearby candidate within BB where we can stick the note. */
- static void
- force_move_args_size_note (basic_block bb, rtx_insn *prev, rtx_insn *insn)
- {
- rtx note;
- rtx_insn *test, *next_candidate, *prev_candidate;
- /* If PREV exists, tail-call to the logic in the other function. */
- if (prev)
- {
- maybe_move_args_size_note (prev, insn, false);
- return;
- }
- /* First, make sure there's anything that needs doing. */
- note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
- if (note == NULL)
- return;
- /* We need to find a spot between the previous and next exception points
- where we can place the note and "properly" deallocate the arguments. */
- next_candidate = prev_candidate = NULL;
- /* It is often the case that we have insns in the order:
- call
- add sp (previous deallocation)
- sub sp (align for next arglist)
- push arg
- and the add/sub cancel. Therefore we begin by searching forward. */
- test = insn;
- while ((test = next_active_insn_bb (bb, test)) != NULL)
- {
- /* Found an existing note: nothing to do. */
- if (find_reg_note (test, REG_ARGS_SIZE, NULL_RTX))
- return;
- /* Found something that affects unwinding. Stop searching. */
- if (CALL_P (test) || !insn_nothrow_p (test))
- break;
- if (next_candidate == NULL)
- next_candidate = test;
- }
- test = insn;
- while ((test = prev_active_insn_bb (bb, test)) != NULL)
- {
- rtx tnote;
- /* Found a place that seems logical to adjust the stack. */
- tnote = find_reg_note (test, REG_ARGS_SIZE, NULL_RTX);
- if (tnote)
- {
- XEXP (tnote, 0) = XEXP (note, 0);
- return;
- }
- if (prev_candidate == NULL)
- prev_candidate = test;
- /* Found something that affects unwinding. Stop searching. */
- if (CALL_P (test) || !insn_nothrow_p (test))
- break;
- }
- if (prev_candidate)
- test = prev_candidate;
- else if (next_candidate)
- test = next_candidate;
- else
- {
- /* ??? We *must* have a place, lest we ICE on the lost adjustment.
- Options are: dummy clobber insn, nop, or prevent the removal of
- the sp += 0 insn. */
- /* TODO: Find another way to indicate to the dwarf2 code that we
- have not in fact lost an adjustment. */
- test = emit_insn_before (gen_rtx_CLOBBER (VOIDmode, const0_rtx), insn);
- }
- add_reg_note (test, REG_ARGS_SIZE, XEXP (note, 0));
- }
- /* Subroutine of combine_stack_adjustments, called for each basic block. */
- static void
- combine_stack_adjustments_for_block (basic_block bb)
- {
- HOST_WIDE_INT last_sp_adjust = 0;
- rtx_insn *last_sp_set = NULL;
- rtx_insn *last2_sp_set = NULL;
- struct csa_reflist *reflist = NULL;
- rtx_insn *insn, *next;
- rtx set;
- bool end_of_block = false;
- for (insn = BB_HEAD (bb); !end_of_block ; insn = next)
- {
- end_of_block = insn == BB_END (bb);
- next = NEXT_INSN (insn);
- if (! INSN_P (insn))
- continue;
- set = single_set_for_csa (insn);
- if (set)
- {
- rtx dest = SET_DEST (set);
- rtx src = SET_SRC (set);
- /* Find constant additions to the stack pointer. */
- if (dest == stack_pointer_rtx
- && GET_CODE (src) == PLUS
- && XEXP (src, 0) == stack_pointer_rtx
- && CONST_INT_P (XEXP (src, 1)))
- {
- HOST_WIDE_INT this_adjust = INTVAL (XEXP (src, 1));
- /* If we've not seen an adjustment previously, record
- it now and continue. */
- if (! last_sp_set)
- {
- last_sp_set = insn;
- last_sp_adjust = this_adjust;
- continue;
- }
- /* If not all recorded refs can be adjusted, or the
- adjustment is now too large for a constant addition,
- we cannot merge the two stack adjustments.
- Also we need to be careful to not move stack pointer
- such that we create stack accesses outside the allocated
- area. We can combine an allocation into the first insn,
- or a deallocation into the second insn. We can not
- combine an allocation followed by a deallocation.
- The only somewhat frequent occurrence of the later is when
- a function allocates a stack frame but does not use it.
- For this case, we would need to analyze rtl stream to be
- sure that allocated area is really unused. This means not
- only checking the memory references, but also all registers
- or global memory references possibly containing a stack
- frame address.
- Perhaps the best way to address this problem is to teach
- gcc not to allocate stack for objects never used. */
- /* Combine an allocation into the first instruction. */
- if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0)
- {
- if (no_unhandled_cfa (insn)
- && try_apply_stack_adjustment (last_sp_set, reflist,
- last_sp_adjust
- + this_adjust,
- this_adjust))
- {
- /* It worked! */
- maybe_move_args_size_note (last_sp_set, insn, false);
- maybe_merge_cfa_adjust (last_sp_set, insn, false);
- delete_insn (insn);
- last_sp_adjust += this_adjust;
- continue;
- }
- }
- /* Otherwise we have a deallocation. Do not combine with
- a previous allocation. Combine into the second insn. */
- else if (STACK_GROWS_DOWNWARD
- ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
- {
- if (no_unhandled_cfa (last_sp_set)
- && try_apply_stack_adjustment (insn, reflist,
- last_sp_adjust
- + this_adjust,
- -last_sp_adjust))
- {
- /* It worked! */
- maybe_move_args_size_note (insn, last_sp_set, true);
- maybe_merge_cfa_adjust (insn, last_sp_set, true);
- delete_insn (last_sp_set);
- last_sp_set = insn;
- last_sp_adjust += this_adjust;
- free_csa_reflist (reflist);
- reflist = NULL;
- continue;
- }
- }
- /* Combination failed. Restart processing from here. If
- deallocation+allocation conspired to cancel, we can
- delete the old deallocation insn. */
- if (last_sp_set)
- {
- if (last_sp_adjust == 0 && no_unhandled_cfa (last_sp_set))
- {
- maybe_move_args_size_note (insn, last_sp_set, true);
- maybe_merge_cfa_adjust (insn, last_sp_set, true);
- delete_insn (last_sp_set);
- }
- else
- last2_sp_set = last_sp_set;
- }
- free_csa_reflist (reflist);
- reflist = NULL;
- last_sp_set = insn;
- last_sp_adjust = this_adjust;
- continue;
- }
- /* Find a store with pre-(dec|inc)rement or pre-modify of exactly
- the previous adjustment and turn it into a simple store. This
- is equivalent to anticipating the stack adjustment so this must
- be an allocation. */
- if (MEM_P (dest)
- && ((STACK_GROWS_DOWNWARD
- ? (GET_CODE (XEXP (dest, 0)) == PRE_DEC
- && last_sp_adjust
- == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest)))
- : (GET_CODE (XEXP (dest, 0)) == PRE_INC
- && last_sp_adjust
- == -(HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest))))
- || ((STACK_GROWS_DOWNWARD
- ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
- && GET_CODE (XEXP (dest, 0)) == PRE_MODIFY
- && GET_CODE (XEXP (XEXP (dest, 0), 1)) == PLUS
- && XEXP (XEXP (XEXP (dest, 0), 1), 0)
- == stack_pointer_rtx
- && GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
- == CONST_INT
- && INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1))
- == -last_sp_adjust))
- && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
- && !reg_mentioned_p (stack_pointer_rtx, src)
- && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
- && try_apply_stack_adjustment (insn, reflist, 0,
- -last_sp_adjust))
- {
- if (last2_sp_set)
- maybe_move_args_size_note (last2_sp_set, last_sp_set, false);
- else
- maybe_move_args_size_note (insn, last_sp_set, true);
- delete_insn (last_sp_set);
- free_csa_reflist (reflist);
- reflist = NULL;
- last_sp_set = NULL;
- last_sp_adjust = 0;
- continue;
- }
- }
- if (!CALL_P (insn) && last_sp_set
- && record_stack_refs (insn, &reflist))
- continue;
- /* Otherwise, we were not able to process the instruction.
- Do not continue collecting data across such a one. */
- if (last_sp_set
- && (CALL_P (insn)
- || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
- {
- if (last_sp_set && last_sp_adjust == 0)
- {
- force_move_args_size_note (bb, last2_sp_set, last_sp_set);
- delete_insn (last_sp_set);
- }
- free_csa_reflist (reflist);
- reflist = NULL;
- last2_sp_set = NULL;
- last_sp_set = NULL;
- last_sp_adjust = 0;
- }
- }
- if (last_sp_set && last_sp_adjust == 0)
- {
- force_move_args_size_note (bb, last2_sp_set, last_sp_set);
- delete_insn (last_sp_set);
- }
- if (reflist)
- free_csa_reflist (reflist);
- }
- static unsigned int
- rest_of_handle_stack_adjustments (void)
- {
- df_note_add_problem ();
- df_analyze ();
- combine_stack_adjustments ();
- return 0;
- }
- namespace {
- const pass_data pass_data_stack_adjustments =
- {
- RTL_PASS, /* type */
- "csa", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_COMBINE_STACK_ADJUST, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_df_finish, /* todo_flags_finish */
- };
- class pass_stack_adjustments : public rtl_opt_pass
- {
- public:
- pass_stack_adjustments (gcc::context *ctxt)
- : rtl_opt_pass (pass_data_stack_adjustments, ctxt)
- {}
- /* opt_pass methods: */
- virtual bool gate (function *);
- virtual unsigned int execute (function *)
- {
- return rest_of_handle_stack_adjustments ();
- }
- }; // class pass_stack_adjustments
- bool
- pass_stack_adjustments::gate (function *)
- {
- /* This is kind of a heuristic. We need to run combine_stack_adjustments
- even for machines with possibly nonzero TARGET_RETURN_POPS_ARGS
- and ACCUMULATE_OUTGOING_ARGS. We expect that only ports having
- push instructions will have popping returns. */
- #ifndef PUSH_ROUNDING
- if (ACCUMULATE_OUTGOING_ARGS)
- return false;
- #endif
- return flag_combine_stack_adjustments;
- }
- } // anon namespace
- rtl_opt_pass *
- make_pass_stack_adjustments (gcc::context *ctxt)
- {
- return new pass_stack_adjustments (ctxt);
- }
|