1*38fd1498Szrj /* Combine stack adjustments.
2*38fd1498Szrj Copyright (C) 1987-2018 Free Software Foundation, Inc.
3*38fd1498Szrj
4*38fd1498Szrj This file is part of GCC.
5*38fd1498Szrj
6*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
7*38fd1498Szrj the terms of the GNU General Public License as published by the Free
8*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
9*38fd1498Szrj version.
10*38fd1498Szrj
11*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14*38fd1498Szrj for more details.
15*38fd1498Szrj
16*38fd1498Szrj You should have received a copy of the GNU General Public License
17*38fd1498Szrj along with GCC; see the file COPYING3. If not see
18*38fd1498Szrj <http://www.gnu.org/licenses/>. */
19*38fd1498Szrj
20*38fd1498Szrj /* Track stack adjustments and stack memory references. Attempt to
21*38fd1498Szrj reduce the number of stack adjustments by back-propagating across
22*38fd1498Szrj the memory references.
23*38fd1498Szrj
24*38fd1498Szrj This is intended primarily for use with targets that do not define
25*38fd1498Szrj ACCUMULATE_OUTGOING_ARGS. It is of significantly more value to
26*38fd1498Szrj targets that define PREFERRED_STACK_BOUNDARY more aligned than
27*38fd1498Szrj STACK_BOUNDARY (e.g. x86), or if not all registers can be pushed
28*38fd1498Szrj (e.g. x86 fp regs) which would ordinarily have to be implemented
29*38fd1498Szrj as a sub/mov pair due to restrictions in calls.c.
30*38fd1498Szrj
31*38fd1498Szrj Propagation stops when any of the insns that need adjusting are
32*38fd1498Szrj (a) no longer valid because we've exceeded their range, (b) a
33*38fd1498Szrj non-trivial push instruction, or (c) a call instruction.
34*38fd1498Szrj
35*38fd1498Szrj Restriction B is based on the assumption that push instructions
36*38fd1498Szrj are smaller or faster. If a port really wants to remove all
37*38fd1498Szrj pushes, it should have defined ACCUMULATE_OUTGOING_ARGS. The
38*38fd1498Szrj one exception that is made is for an add immediately followed
39*38fd1498Szrj by a push. */
40*38fd1498Szrj
41*38fd1498Szrj #include "config.h"
42*38fd1498Szrj #include "system.h"
43*38fd1498Szrj #include "coretypes.h"
44*38fd1498Szrj #include "backend.h"
45*38fd1498Szrj #include "rtl.h"
46*38fd1498Szrj #include "df.h"
47*38fd1498Szrj #include "insn-config.h"
48*38fd1498Szrj #include "memmodel.h"
49*38fd1498Szrj #include "emit-rtl.h"
50*38fd1498Szrj #include "recog.h"
51*38fd1498Szrj #include "cfgrtl.h"
52*38fd1498Szrj #include "tree-pass.h"
53*38fd1498Szrj #include "rtl-iter.h"
54*38fd1498Szrj
55*38fd1498Szrj
56*38fd1498Szrj /* This structure records two kinds of stack references between stack
57*38fd1498Szrj adjusting instructions: stack references in memory addresses for
58*38fd1498Szrj regular insns and all stack references for debug insns. */
59*38fd1498Szrj
60*38fd1498Szrj struct csa_reflist
61*38fd1498Szrj {
62*38fd1498Szrj HOST_WIDE_INT sp_offset;
63*38fd1498Szrj rtx_insn *insn;
64*38fd1498Szrj rtx *ref;
65*38fd1498Szrj struct csa_reflist *next;
66*38fd1498Szrj };
67*38fd1498Szrj
68*38fd1498Szrj static int stack_memref_p (rtx);
69*38fd1498Szrj static rtx single_set_for_csa (rtx_insn *);
70*38fd1498Szrj static void free_csa_reflist (struct csa_reflist *);
71*38fd1498Szrj static struct csa_reflist *record_one_stack_ref (rtx_insn *, rtx *,
72*38fd1498Szrj struct csa_reflist *);
73*38fd1498Szrj static int try_apply_stack_adjustment (rtx_insn *, struct csa_reflist *,
74*38fd1498Szrj HOST_WIDE_INT, HOST_WIDE_INT);
75*38fd1498Szrj static void combine_stack_adjustments_for_block (basic_block);
76*38fd1498Szrj
77*38fd1498Szrj
78*38fd1498Szrj /* Main entry point for stack adjustment combination. */
79*38fd1498Szrj
80*38fd1498Szrj static void
combine_stack_adjustments(void)81*38fd1498Szrj combine_stack_adjustments (void)
82*38fd1498Szrj {
83*38fd1498Szrj basic_block bb;
84*38fd1498Szrj
85*38fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
86*38fd1498Szrj combine_stack_adjustments_for_block (bb);
87*38fd1498Szrj }
88*38fd1498Szrj
89*38fd1498Szrj /* Recognize a MEM of the form (sp) or (plus sp const). */
90*38fd1498Szrj
91*38fd1498Szrj static int
stack_memref_p(rtx x)92*38fd1498Szrj stack_memref_p (rtx x)
93*38fd1498Szrj {
94*38fd1498Szrj if (!MEM_P (x))
95*38fd1498Szrj return 0;
96*38fd1498Szrj x = XEXP (x, 0);
97*38fd1498Szrj
98*38fd1498Szrj if (x == stack_pointer_rtx)
99*38fd1498Szrj return 1;
100*38fd1498Szrj if (GET_CODE (x) == PLUS
101*38fd1498Szrj && XEXP (x, 0) == stack_pointer_rtx
102*38fd1498Szrj && CONST_INT_P (XEXP (x, 1)))
103*38fd1498Szrj return 1;
104*38fd1498Szrj
105*38fd1498Szrj return 0;
106*38fd1498Szrj }
107*38fd1498Szrj
108*38fd1498Szrj /* Recognize either normal single_set or the hack in i386.md for
109*38fd1498Szrj tying fp and sp adjustments. */
110*38fd1498Szrj
111*38fd1498Szrj static rtx
single_set_for_csa(rtx_insn * insn)112*38fd1498Szrj single_set_for_csa (rtx_insn *insn)
113*38fd1498Szrj {
114*38fd1498Szrj int i;
115*38fd1498Szrj rtx tmp = single_set (insn);
116*38fd1498Szrj if (tmp)
117*38fd1498Szrj return tmp;
118*38fd1498Szrj
119*38fd1498Szrj if (!NONJUMP_INSN_P (insn)
120*38fd1498Szrj || GET_CODE (PATTERN (insn)) != PARALLEL)
121*38fd1498Szrj return NULL_RTX;
122*38fd1498Szrj
123*38fd1498Szrj tmp = PATTERN (insn);
124*38fd1498Szrj if (GET_CODE (XVECEXP (tmp, 0, 0)) != SET)
125*38fd1498Szrj return NULL_RTX;
126*38fd1498Szrj
127*38fd1498Szrj for (i = 1; i < XVECLEN (tmp, 0); ++i)
128*38fd1498Szrj {
129*38fd1498Szrj rtx this_rtx = XVECEXP (tmp, 0, i);
130*38fd1498Szrj
131*38fd1498Szrj /* The special case is allowing a no-op set. */
132*38fd1498Szrj if (GET_CODE (this_rtx) == SET
133*38fd1498Szrj && SET_SRC (this_rtx) == SET_DEST (this_rtx))
134*38fd1498Szrj ;
135*38fd1498Szrj else if (GET_CODE (this_rtx) != CLOBBER
136*38fd1498Szrj && GET_CODE (this_rtx) != USE)
137*38fd1498Szrj return NULL_RTX;
138*38fd1498Szrj }
139*38fd1498Szrj
140*38fd1498Szrj return XVECEXP (tmp, 0, 0);
141*38fd1498Szrj }
142*38fd1498Szrj
143*38fd1498Szrj /* Free the list of csa_reflist nodes. */
144*38fd1498Szrj
145*38fd1498Szrj static void
free_csa_reflist(struct csa_reflist * reflist)146*38fd1498Szrj free_csa_reflist (struct csa_reflist *reflist)
147*38fd1498Szrj {
148*38fd1498Szrj struct csa_reflist *next;
149*38fd1498Szrj for (; reflist ; reflist = next)
150*38fd1498Szrj {
151*38fd1498Szrj next = reflist->next;
152*38fd1498Szrj free (reflist);
153*38fd1498Szrj }
154*38fd1498Szrj }
155*38fd1498Szrj
156*38fd1498Szrj /* Create a new csa_reflist node from the given stack reference.
157*38fd1498Szrj It is already known that the reference is either a MEM satisfying the
158*38fd1498Szrj predicate stack_memref_p or a REG representing the stack pointer. */
159*38fd1498Szrj
160*38fd1498Szrj static struct csa_reflist *
record_one_stack_ref(rtx_insn * insn,rtx * ref,struct csa_reflist * next_reflist)161*38fd1498Szrj record_one_stack_ref (rtx_insn *insn, rtx *ref, struct csa_reflist *next_reflist)
162*38fd1498Szrj {
163*38fd1498Szrj struct csa_reflist *ml;
164*38fd1498Szrj
165*38fd1498Szrj ml = XNEW (struct csa_reflist);
166*38fd1498Szrj
167*38fd1498Szrj if (REG_P (*ref) || XEXP (*ref, 0) == stack_pointer_rtx)
168*38fd1498Szrj ml->sp_offset = 0;
169*38fd1498Szrj else
170*38fd1498Szrj ml->sp_offset = INTVAL (XEXP (XEXP (*ref, 0), 1));
171*38fd1498Szrj
172*38fd1498Szrj ml->insn = insn;
173*38fd1498Szrj ml->ref = ref;
174*38fd1498Szrj ml->next = next_reflist;
175*38fd1498Szrj
176*38fd1498Szrj return ml;
177*38fd1498Szrj }
178*38fd1498Szrj
179*38fd1498Szrj /* We only know how to adjust the CFA; no other frame-related changes
180*38fd1498Szrj may appear in any insn to be deleted. */
181*38fd1498Szrj
182*38fd1498Szrj static bool
no_unhandled_cfa(rtx_insn * insn)183*38fd1498Szrj no_unhandled_cfa (rtx_insn *insn)
184*38fd1498Szrj {
185*38fd1498Szrj if (!RTX_FRAME_RELATED_P (insn))
186*38fd1498Szrj return true;
187*38fd1498Szrj
188*38fd1498Szrj /* No CFA notes at all is a legacy interpretation like
189*38fd1498Szrj FRAME_RELATED_EXPR, and is context sensitive within
190*38fd1498Szrj the prologue state machine. We can't handle that here. */
191*38fd1498Szrj bool has_cfa_adjust = false;
192*38fd1498Szrj
193*38fd1498Szrj for (rtx link = REG_NOTES (insn); link; link = XEXP (link, 1))
194*38fd1498Szrj switch (REG_NOTE_KIND (link))
195*38fd1498Szrj {
196*38fd1498Szrj default:
197*38fd1498Szrj break;
198*38fd1498Szrj case REG_CFA_ADJUST_CFA:
199*38fd1498Szrj has_cfa_adjust = true;
200*38fd1498Szrj break;
201*38fd1498Szrj
202*38fd1498Szrj case REG_FRAME_RELATED_EXPR:
203*38fd1498Szrj case REG_CFA_DEF_CFA:
204*38fd1498Szrj case REG_CFA_OFFSET:
205*38fd1498Szrj case REG_CFA_REGISTER:
206*38fd1498Szrj case REG_CFA_EXPRESSION:
207*38fd1498Szrj case REG_CFA_RESTORE:
208*38fd1498Szrj case REG_CFA_SET_VDRAP:
209*38fd1498Szrj case REG_CFA_WINDOW_SAVE:
210*38fd1498Szrj case REG_CFA_FLUSH_QUEUE:
211*38fd1498Szrj case REG_CFA_TOGGLE_RA_MANGLE:
212*38fd1498Szrj return false;
213*38fd1498Szrj }
214*38fd1498Szrj
215*38fd1498Szrj return has_cfa_adjust;
216*38fd1498Szrj }
217*38fd1498Szrj
218*38fd1498Szrj /* Attempt to apply ADJUST to the stack adjusting insn INSN, as well
219*38fd1498Szrj as each of the memories and stack references in REFLIST. Return true
220*38fd1498Szrj on success. */
221*38fd1498Szrj
222*38fd1498Szrj static int
try_apply_stack_adjustment(rtx_insn * insn,struct csa_reflist * reflist,HOST_WIDE_INT new_adjust,HOST_WIDE_INT delta)223*38fd1498Szrj try_apply_stack_adjustment (rtx_insn *insn, struct csa_reflist *reflist,
224*38fd1498Szrj HOST_WIDE_INT new_adjust, HOST_WIDE_INT delta)
225*38fd1498Szrj {
226*38fd1498Szrj struct csa_reflist *ml;
227*38fd1498Szrj rtx set;
228*38fd1498Szrj
229*38fd1498Szrj set = single_set_for_csa (insn);
230*38fd1498Szrj if (MEM_P (SET_DEST (set)))
231*38fd1498Szrj validate_change (insn, &SET_DEST (set),
232*38fd1498Szrj replace_equiv_address (SET_DEST (set), stack_pointer_rtx),
233*38fd1498Szrj 1);
234*38fd1498Szrj else
235*38fd1498Szrj validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust), 1);
236*38fd1498Szrj
237*38fd1498Szrj for (ml = reflist; ml ; ml = ml->next)
238*38fd1498Szrj {
239*38fd1498Szrj rtx new_addr = plus_constant (Pmode, stack_pointer_rtx,
240*38fd1498Szrj ml->sp_offset - delta);
241*38fd1498Szrj rtx new_val;
242*38fd1498Szrj
243*38fd1498Szrj if (MEM_P (*ml->ref))
244*38fd1498Szrj new_val = replace_equiv_address_nv (*ml->ref, new_addr);
245*38fd1498Szrj else if (GET_MODE (*ml->ref) == GET_MODE (stack_pointer_rtx))
246*38fd1498Szrj new_val = new_addr;
247*38fd1498Szrj else
248*38fd1498Szrj new_val = lowpart_subreg (GET_MODE (*ml->ref), new_addr,
249*38fd1498Szrj GET_MODE (new_addr));
250*38fd1498Szrj validate_change (ml->insn, ml->ref, new_val, 1);
251*38fd1498Szrj }
252*38fd1498Szrj
253*38fd1498Szrj if (apply_change_group ())
254*38fd1498Szrj {
255*38fd1498Szrj /* Succeeded. Update our knowledge of the stack references. */
256*38fd1498Szrj for (ml = reflist; ml ; ml = ml->next)
257*38fd1498Szrj ml->sp_offset -= delta;
258*38fd1498Szrj
259*38fd1498Szrj return 1;
260*38fd1498Szrj }
261*38fd1498Szrj else
262*38fd1498Szrj return 0;
263*38fd1498Szrj }
264*38fd1498Szrj
265*38fd1498Szrj /* For non-debug insns, record all stack memory references in INSN
266*38fd1498Szrj and return true if there were no other (unrecorded) references to the
267*38fd1498Szrj stack pointer. For debug insns, record all stack references regardless
268*38fd1498Szrj of context and unconditionally return true. */
269*38fd1498Szrj
270*38fd1498Szrj static bool
record_stack_refs(rtx_insn * insn,struct csa_reflist ** reflist)271*38fd1498Szrj record_stack_refs (rtx_insn *insn, struct csa_reflist **reflist)
272*38fd1498Szrj {
273*38fd1498Szrj subrtx_ptr_iterator::array_type array;
274*38fd1498Szrj FOR_EACH_SUBRTX_PTR (iter, array, &PATTERN (insn), NONCONST)
275*38fd1498Szrj {
276*38fd1498Szrj rtx *loc = *iter;
277*38fd1498Szrj rtx x = *loc;
278*38fd1498Szrj switch (GET_CODE (x))
279*38fd1498Szrj {
280*38fd1498Szrj case MEM:
281*38fd1498Szrj if (!reg_mentioned_p (stack_pointer_rtx, x))
282*38fd1498Szrj iter.skip_subrtxes ();
283*38fd1498Szrj /* We are not able to handle correctly all possible memrefs
284*38fd1498Szrj containing stack pointer, so this check is necessary. */
285*38fd1498Szrj else if (stack_memref_p (x))
286*38fd1498Szrj {
287*38fd1498Szrj *reflist = record_one_stack_ref (insn, loc, *reflist);
288*38fd1498Szrj iter.skip_subrtxes ();
289*38fd1498Szrj }
290*38fd1498Szrj /* Try harder for DEBUG_INSNs, handle e.g.
291*38fd1498Szrj (mem (mem (sp + 16) + 4). */
292*38fd1498Szrj else if (!DEBUG_INSN_P (insn))
293*38fd1498Szrj return false;
294*38fd1498Szrj break;
295*38fd1498Szrj
296*38fd1498Szrj case REG:
297*38fd1498Szrj /* ??? We want be able to handle non-memory stack pointer
298*38fd1498Szrj references later. For now just discard all insns referring to
299*38fd1498Szrj stack pointer outside mem expressions. We would probably
300*38fd1498Szrj want to teach validate_replace to simplify expressions first.
301*38fd1498Szrj
302*38fd1498Szrj We can't just compare with STACK_POINTER_RTX because the
303*38fd1498Szrj reference to the stack pointer might be in some other mode.
304*38fd1498Szrj In particular, an explicit clobber in an asm statement will
305*38fd1498Szrj result in a QImode clobber.
306*38fd1498Szrj
307*38fd1498Szrj In DEBUG_INSNs, we want to replace all occurrences, otherwise
308*38fd1498Szrj they will cause -fcompare-debug failures. */
309*38fd1498Szrj if (REGNO (x) == STACK_POINTER_REGNUM)
310*38fd1498Szrj {
311*38fd1498Szrj if (!DEBUG_INSN_P (insn))
312*38fd1498Szrj return false;
313*38fd1498Szrj *reflist = record_one_stack_ref (insn, loc, *reflist);
314*38fd1498Szrj }
315*38fd1498Szrj break;
316*38fd1498Szrj
317*38fd1498Szrj default:
318*38fd1498Szrj break;
319*38fd1498Szrj }
320*38fd1498Szrj }
321*38fd1498Szrj return true;
322*38fd1498Szrj }
323*38fd1498Szrj
324*38fd1498Szrj /* If INSN has a REG_ARGS_SIZE note, move it to LAST.
325*38fd1498Szrj AFTER is true iff LAST follows INSN in the instruction stream. */
326*38fd1498Szrj
327*38fd1498Szrj static void
maybe_move_args_size_note(rtx_insn * last,rtx_insn * insn,bool after)328*38fd1498Szrj maybe_move_args_size_note (rtx_insn *last, rtx_insn *insn, bool after)
329*38fd1498Szrj {
330*38fd1498Szrj rtx note, last_note;
331*38fd1498Szrj
332*38fd1498Szrj note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
333*38fd1498Szrj if (note == NULL)
334*38fd1498Szrj return;
335*38fd1498Szrj
336*38fd1498Szrj last_note = find_reg_note (last, REG_ARGS_SIZE, NULL_RTX);
337*38fd1498Szrj if (last_note)
338*38fd1498Szrj {
339*38fd1498Szrj /* The ARGS_SIZE notes are *not* cumulative. They represent an
340*38fd1498Szrj absolute value, and the "most recent" note wins. */
341*38fd1498Szrj if (!after)
342*38fd1498Szrj XEXP (last_note, 0) = XEXP (note, 0);
343*38fd1498Szrj }
344*38fd1498Szrj else
345*38fd1498Szrj add_reg_note (last, REG_ARGS_SIZE, XEXP (note, 0));
346*38fd1498Szrj }
347*38fd1498Szrj
348*38fd1498Szrj /* Merge any REG_CFA_ADJUST_CFA note from SRC into DST.
349*38fd1498Szrj AFTER is true iff DST follows SRC in the instruction stream. */
350*38fd1498Szrj
351*38fd1498Szrj static void
maybe_merge_cfa_adjust(rtx_insn * dst,rtx_insn * src,bool after)352*38fd1498Szrj maybe_merge_cfa_adjust (rtx_insn *dst, rtx_insn *src, bool after)
353*38fd1498Szrj {
354*38fd1498Szrj rtx snote = NULL, dnote = NULL;
355*38fd1498Szrj rtx sexp, dexp;
356*38fd1498Szrj rtx exp1, exp2;
357*38fd1498Szrj
358*38fd1498Szrj if (RTX_FRAME_RELATED_P (src))
359*38fd1498Szrj snote = find_reg_note (src, REG_CFA_ADJUST_CFA, NULL_RTX);
360*38fd1498Szrj if (snote == NULL)
361*38fd1498Szrj return;
362*38fd1498Szrj sexp = XEXP (snote, 0);
363*38fd1498Szrj
364*38fd1498Szrj if (RTX_FRAME_RELATED_P (dst))
365*38fd1498Szrj dnote = find_reg_note (dst, REG_CFA_ADJUST_CFA, NULL_RTX);
366*38fd1498Szrj if (dnote == NULL)
367*38fd1498Szrj {
368*38fd1498Szrj add_reg_note (dst, REG_CFA_ADJUST_CFA, sexp);
369*38fd1498Szrj return;
370*38fd1498Szrj }
371*38fd1498Szrj dexp = XEXP (dnote, 0);
372*38fd1498Szrj
373*38fd1498Szrj gcc_assert (GET_CODE (sexp) == SET);
374*38fd1498Szrj gcc_assert (GET_CODE (dexp) == SET);
375*38fd1498Szrj
376*38fd1498Szrj if (after)
377*38fd1498Szrj exp1 = dexp, exp2 = sexp;
378*38fd1498Szrj else
379*38fd1498Szrj exp1 = sexp, exp2 = dexp;
380*38fd1498Szrj
381*38fd1498Szrj SET_SRC (exp1) = simplify_replace_rtx (SET_SRC (exp1), SET_DEST (exp2),
382*38fd1498Szrj SET_SRC (exp2));
383*38fd1498Szrj XEXP (dnote, 0) = exp1;
384*38fd1498Szrj }
385*38fd1498Szrj
386*38fd1498Szrj /* Return the next (or previous) active insn within BB. */
387*38fd1498Szrj
388*38fd1498Szrj static rtx_insn *
prev_active_insn_bb(basic_block bb,rtx_insn * insn)389*38fd1498Szrj prev_active_insn_bb (basic_block bb, rtx_insn *insn)
390*38fd1498Szrj {
391*38fd1498Szrj for (insn = PREV_INSN (insn);
392*38fd1498Szrj insn != PREV_INSN (BB_HEAD (bb));
393*38fd1498Szrj insn = PREV_INSN (insn))
394*38fd1498Szrj if (active_insn_p (insn))
395*38fd1498Szrj return insn;
396*38fd1498Szrj return NULL;
397*38fd1498Szrj }
398*38fd1498Szrj
399*38fd1498Szrj static rtx_insn *
next_active_insn_bb(basic_block bb,rtx_insn * insn)400*38fd1498Szrj next_active_insn_bb (basic_block bb, rtx_insn *insn)
401*38fd1498Szrj {
402*38fd1498Szrj for (insn = NEXT_INSN (insn);
403*38fd1498Szrj insn != NEXT_INSN (BB_END (bb));
404*38fd1498Szrj insn = NEXT_INSN (insn))
405*38fd1498Szrj if (active_insn_p (insn))
406*38fd1498Szrj return insn;
407*38fd1498Szrj return NULL;
408*38fd1498Szrj }
409*38fd1498Szrj
410*38fd1498Szrj /* If INSN has a REG_ARGS_SIZE note, if possible move it to PREV. Otherwise
411*38fd1498Szrj search for a nearby candidate within BB where we can stick the note. */
412*38fd1498Szrj
413*38fd1498Szrj static void
force_move_args_size_note(basic_block bb,rtx_insn * prev,rtx_insn * insn)414*38fd1498Szrj force_move_args_size_note (basic_block bb, rtx_insn *prev, rtx_insn *insn)
415*38fd1498Szrj {
416*38fd1498Szrj rtx note;
417*38fd1498Szrj rtx_insn *test, *next_candidate, *prev_candidate;
418*38fd1498Szrj
419*38fd1498Szrj /* If PREV exists, tail-call to the logic in the other function. */
420*38fd1498Szrj if (prev)
421*38fd1498Szrj {
422*38fd1498Szrj maybe_move_args_size_note (prev, insn, false);
423*38fd1498Szrj return;
424*38fd1498Szrj }
425*38fd1498Szrj
426*38fd1498Szrj /* First, make sure there's anything that needs doing. */
427*38fd1498Szrj note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
428*38fd1498Szrj if (note == NULL)
429*38fd1498Szrj return;
430*38fd1498Szrj
431*38fd1498Szrj /* We need to find a spot between the previous and next exception points
432*38fd1498Szrj where we can place the note and "properly" deallocate the arguments. */
433*38fd1498Szrj next_candidate = prev_candidate = NULL;
434*38fd1498Szrj
435*38fd1498Szrj /* It is often the case that we have insns in the order:
436*38fd1498Szrj call
437*38fd1498Szrj add sp (previous deallocation)
438*38fd1498Szrj sub sp (align for next arglist)
439*38fd1498Szrj push arg
440*38fd1498Szrj and the add/sub cancel. Therefore we begin by searching forward. */
441*38fd1498Szrj
442*38fd1498Szrj test = insn;
443*38fd1498Szrj while ((test = next_active_insn_bb (bb, test)) != NULL)
444*38fd1498Szrj {
445*38fd1498Szrj /* Found an existing note: nothing to do. */
446*38fd1498Szrj if (find_reg_note (test, REG_ARGS_SIZE, NULL_RTX))
447*38fd1498Szrj return;
448*38fd1498Szrj /* Found something that affects unwinding. Stop searching. */
449*38fd1498Szrj if (CALL_P (test) || !insn_nothrow_p (test))
450*38fd1498Szrj break;
451*38fd1498Szrj if (next_candidate == NULL)
452*38fd1498Szrj next_candidate = test;
453*38fd1498Szrj }
454*38fd1498Szrj
455*38fd1498Szrj test = insn;
456*38fd1498Szrj while ((test = prev_active_insn_bb (bb, test)) != NULL)
457*38fd1498Szrj {
458*38fd1498Szrj rtx tnote;
459*38fd1498Szrj /* Found a place that seems logical to adjust the stack. */
460*38fd1498Szrj tnote = find_reg_note (test, REG_ARGS_SIZE, NULL_RTX);
461*38fd1498Szrj if (tnote)
462*38fd1498Szrj {
463*38fd1498Szrj XEXP (tnote, 0) = XEXP (note, 0);
464*38fd1498Szrj return;
465*38fd1498Szrj }
466*38fd1498Szrj if (prev_candidate == NULL)
467*38fd1498Szrj prev_candidate = test;
468*38fd1498Szrj /* Found something that affects unwinding. Stop searching. */
469*38fd1498Szrj if (CALL_P (test) || !insn_nothrow_p (test))
470*38fd1498Szrj break;
471*38fd1498Szrj }
472*38fd1498Szrj
473*38fd1498Szrj if (prev_candidate)
474*38fd1498Szrj test = prev_candidate;
475*38fd1498Szrj else if (next_candidate)
476*38fd1498Szrj test = next_candidate;
477*38fd1498Szrj else
478*38fd1498Szrj {
479*38fd1498Szrj /* ??? We *must* have a place, lest we ICE on the lost adjustment.
480*38fd1498Szrj Options are: dummy clobber insn, nop, or prevent the removal of
481*38fd1498Szrj the sp += 0 insn. */
482*38fd1498Szrj /* TODO: Find another way to indicate to the dwarf2 code that we
483*38fd1498Szrj have not in fact lost an adjustment. */
484*38fd1498Szrj test = emit_insn_before (gen_rtx_CLOBBER (VOIDmode, const0_rtx), insn);
485*38fd1498Szrj }
486*38fd1498Szrj add_reg_note (test, REG_ARGS_SIZE, XEXP (note, 0));
487*38fd1498Szrj }
488*38fd1498Szrj
489*38fd1498Szrj /* Subroutine of combine_stack_adjustments, called for each basic block. */
490*38fd1498Szrj
491*38fd1498Szrj static void
combine_stack_adjustments_for_block(basic_block bb)492*38fd1498Szrj combine_stack_adjustments_for_block (basic_block bb)
493*38fd1498Szrj {
494*38fd1498Szrj HOST_WIDE_INT last_sp_adjust = 0;
495*38fd1498Szrj rtx_insn *last_sp_set = NULL;
496*38fd1498Szrj rtx_insn *last2_sp_set = NULL;
497*38fd1498Szrj struct csa_reflist *reflist = NULL;
498*38fd1498Szrj rtx_insn *insn, *next;
499*38fd1498Szrj rtx set;
500*38fd1498Szrj bool end_of_block = false;
501*38fd1498Szrj
502*38fd1498Szrj for (insn = BB_HEAD (bb); !end_of_block ; insn = next)
503*38fd1498Szrj {
504*38fd1498Szrj end_of_block = insn == BB_END (bb);
505*38fd1498Szrj next = NEXT_INSN (insn);
506*38fd1498Szrj
507*38fd1498Szrj if (! INSN_P (insn))
508*38fd1498Szrj continue;
509*38fd1498Szrj
510*38fd1498Szrj set = single_set_for_csa (insn);
511*38fd1498Szrj if (set && find_reg_note (insn, REG_STACK_CHECK, NULL_RTX))
512*38fd1498Szrj set = NULL_RTX;
513*38fd1498Szrj if (set)
514*38fd1498Szrj {
515*38fd1498Szrj rtx dest = SET_DEST (set);
516*38fd1498Szrj rtx src = SET_SRC (set);
517*38fd1498Szrj
518*38fd1498Szrj /* Find constant additions to the stack pointer. */
519*38fd1498Szrj if (dest == stack_pointer_rtx
520*38fd1498Szrj && GET_CODE (src) == PLUS
521*38fd1498Szrj && XEXP (src, 0) == stack_pointer_rtx
522*38fd1498Szrj && CONST_INT_P (XEXP (src, 1)))
523*38fd1498Szrj {
524*38fd1498Szrj HOST_WIDE_INT this_adjust = INTVAL (XEXP (src, 1));
525*38fd1498Szrj
526*38fd1498Szrj /* If we've not seen an adjustment previously, record
527*38fd1498Szrj it now and continue. */
528*38fd1498Szrj if (! last_sp_set)
529*38fd1498Szrj {
530*38fd1498Szrj last_sp_set = insn;
531*38fd1498Szrj last_sp_adjust = this_adjust;
532*38fd1498Szrj continue;
533*38fd1498Szrj }
534*38fd1498Szrj
535*38fd1498Szrj /* If not all recorded refs can be adjusted, or the
536*38fd1498Szrj adjustment is now too large for a constant addition,
537*38fd1498Szrj we cannot merge the two stack adjustments.
538*38fd1498Szrj
539*38fd1498Szrj Also we need to be careful to not move stack pointer
540*38fd1498Szrj such that we create stack accesses outside the allocated
541*38fd1498Szrj area. We can combine an allocation into the first insn,
542*38fd1498Szrj or a deallocation into the second insn. We can not
543*38fd1498Szrj combine an allocation followed by a deallocation.
544*38fd1498Szrj
545*38fd1498Szrj The only somewhat frequent occurrence of the later is when
546*38fd1498Szrj a function allocates a stack frame but does not use it.
547*38fd1498Szrj For this case, we would need to analyze rtl stream to be
548*38fd1498Szrj sure that allocated area is really unused. This means not
549*38fd1498Szrj only checking the memory references, but also all registers
550*38fd1498Szrj or global memory references possibly containing a stack
551*38fd1498Szrj frame address.
552*38fd1498Szrj
553*38fd1498Szrj Perhaps the best way to address this problem is to teach
554*38fd1498Szrj gcc not to allocate stack for objects never used. */
555*38fd1498Szrj
556*38fd1498Szrj /* Combine an allocation into the first instruction. */
557*38fd1498Szrj if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0)
558*38fd1498Szrj {
559*38fd1498Szrj if (no_unhandled_cfa (insn)
560*38fd1498Szrj && try_apply_stack_adjustment (last_sp_set, reflist,
561*38fd1498Szrj last_sp_adjust
562*38fd1498Szrj + this_adjust,
563*38fd1498Szrj this_adjust))
564*38fd1498Szrj {
565*38fd1498Szrj /* It worked! */
566*38fd1498Szrj maybe_move_args_size_note (last_sp_set, insn, false);
567*38fd1498Szrj maybe_merge_cfa_adjust (last_sp_set, insn, false);
568*38fd1498Szrj delete_insn (insn);
569*38fd1498Szrj last_sp_adjust += this_adjust;
570*38fd1498Szrj continue;
571*38fd1498Szrj }
572*38fd1498Szrj }
573*38fd1498Szrj
574*38fd1498Szrj /* Otherwise we have a deallocation. Do not combine with
575*38fd1498Szrj a previous allocation. Combine into the second insn. */
576*38fd1498Szrj else if (STACK_GROWS_DOWNWARD
577*38fd1498Szrj ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
578*38fd1498Szrj {
579*38fd1498Szrj if (no_unhandled_cfa (last_sp_set)
580*38fd1498Szrj && try_apply_stack_adjustment (insn, reflist,
581*38fd1498Szrj last_sp_adjust
582*38fd1498Szrj + this_adjust,
583*38fd1498Szrj -last_sp_adjust))
584*38fd1498Szrj {
585*38fd1498Szrj /* It worked! */
586*38fd1498Szrj maybe_move_args_size_note (insn, last_sp_set, true);
587*38fd1498Szrj maybe_merge_cfa_adjust (insn, last_sp_set, true);
588*38fd1498Szrj delete_insn (last_sp_set);
589*38fd1498Szrj last_sp_set = insn;
590*38fd1498Szrj last_sp_adjust += this_adjust;
591*38fd1498Szrj free_csa_reflist (reflist);
592*38fd1498Szrj reflist = NULL;
593*38fd1498Szrj continue;
594*38fd1498Szrj }
595*38fd1498Szrj }
596*38fd1498Szrj
597*38fd1498Szrj /* Combination failed. Restart processing from here. If
598*38fd1498Szrj deallocation+allocation conspired to cancel, we can
599*38fd1498Szrj delete the old deallocation insn. */
600*38fd1498Szrj if (last_sp_set)
601*38fd1498Szrj {
602*38fd1498Szrj if (last_sp_adjust == 0 && no_unhandled_cfa (last_sp_set))
603*38fd1498Szrj {
604*38fd1498Szrj maybe_move_args_size_note (insn, last_sp_set, true);
605*38fd1498Szrj maybe_merge_cfa_adjust (insn, last_sp_set, true);
606*38fd1498Szrj delete_insn (last_sp_set);
607*38fd1498Szrj }
608*38fd1498Szrj else
609*38fd1498Szrj last2_sp_set = last_sp_set;
610*38fd1498Szrj }
611*38fd1498Szrj free_csa_reflist (reflist);
612*38fd1498Szrj reflist = NULL;
613*38fd1498Szrj last_sp_set = insn;
614*38fd1498Szrj last_sp_adjust = this_adjust;
615*38fd1498Szrj continue;
616*38fd1498Szrj }
617*38fd1498Szrj
618*38fd1498Szrj /* Find a store with pre-(dec|inc)rement or pre-modify of exactly
619*38fd1498Szrj the previous adjustment and turn it into a simple store. This
620*38fd1498Szrj is equivalent to anticipating the stack adjustment so this must
621*38fd1498Szrj be an allocation. */
622*38fd1498Szrj if (MEM_P (dest)
623*38fd1498Szrj && ((STACK_GROWS_DOWNWARD
624*38fd1498Szrj ? (GET_CODE (XEXP (dest, 0)) == PRE_DEC
625*38fd1498Szrj && known_eq (last_sp_adjust,
626*38fd1498Szrj GET_MODE_SIZE (GET_MODE (dest))))
627*38fd1498Szrj : (GET_CODE (XEXP (dest, 0)) == PRE_INC
628*38fd1498Szrj && known_eq (-last_sp_adjust,
629*38fd1498Szrj GET_MODE_SIZE (GET_MODE (dest)))))
630*38fd1498Szrj || ((STACK_GROWS_DOWNWARD
631*38fd1498Szrj ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
632*38fd1498Szrj && GET_CODE (XEXP (dest, 0)) == PRE_MODIFY
633*38fd1498Szrj && GET_CODE (XEXP (XEXP (dest, 0), 1)) == PLUS
634*38fd1498Szrj && XEXP (XEXP (XEXP (dest, 0), 1), 0)
635*38fd1498Szrj == stack_pointer_rtx
636*38fd1498Szrj && GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
637*38fd1498Szrj == CONST_INT
638*38fd1498Szrj && INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1))
639*38fd1498Szrj == -last_sp_adjust))
640*38fd1498Szrj && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
641*38fd1498Szrj && !reg_mentioned_p (stack_pointer_rtx, src)
642*38fd1498Szrj && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
643*38fd1498Szrj && try_apply_stack_adjustment (insn, reflist, 0,
644*38fd1498Szrj -last_sp_adjust))
645*38fd1498Szrj {
646*38fd1498Szrj if (last2_sp_set)
647*38fd1498Szrj maybe_move_args_size_note (last2_sp_set, last_sp_set, false);
648*38fd1498Szrj else
649*38fd1498Szrj maybe_move_args_size_note (insn, last_sp_set, true);
650*38fd1498Szrj delete_insn (last_sp_set);
651*38fd1498Szrj free_csa_reflist (reflist);
652*38fd1498Szrj reflist = NULL;
653*38fd1498Szrj last_sp_set = NULL;
654*38fd1498Szrj last_sp_adjust = 0;
655*38fd1498Szrj continue;
656*38fd1498Szrj }
657*38fd1498Szrj }
658*38fd1498Szrj
659*38fd1498Szrj if (!CALL_P (insn) && last_sp_set
660*38fd1498Szrj && record_stack_refs (insn, &reflist))
661*38fd1498Szrj continue;
662*38fd1498Szrj
663*38fd1498Szrj /* Otherwise, we were not able to process the instruction.
664*38fd1498Szrj Do not continue collecting data across such a one. */
665*38fd1498Szrj if (last_sp_set
666*38fd1498Szrj && (CALL_P (insn)
667*38fd1498Szrj || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
668*38fd1498Szrj {
669*38fd1498Szrj if (last_sp_set && last_sp_adjust == 0)
670*38fd1498Szrj {
671*38fd1498Szrj force_move_args_size_note (bb, last2_sp_set, last_sp_set);
672*38fd1498Szrj delete_insn (last_sp_set);
673*38fd1498Szrj }
674*38fd1498Szrj free_csa_reflist (reflist);
675*38fd1498Szrj reflist = NULL;
676*38fd1498Szrj last2_sp_set = NULL;
677*38fd1498Szrj last_sp_set = NULL;
678*38fd1498Szrj last_sp_adjust = 0;
679*38fd1498Szrj }
680*38fd1498Szrj }
681*38fd1498Szrj
682*38fd1498Szrj if (last_sp_set && last_sp_adjust == 0)
683*38fd1498Szrj {
684*38fd1498Szrj force_move_args_size_note (bb, last2_sp_set, last_sp_set);
685*38fd1498Szrj delete_insn (last_sp_set);
686*38fd1498Szrj }
687*38fd1498Szrj
688*38fd1498Szrj if (reflist)
689*38fd1498Szrj free_csa_reflist (reflist);
690*38fd1498Szrj }
691*38fd1498Szrj
692*38fd1498Szrj static unsigned int
rest_of_handle_stack_adjustments(void)693*38fd1498Szrj rest_of_handle_stack_adjustments (void)
694*38fd1498Szrj {
695*38fd1498Szrj df_note_add_problem ();
696*38fd1498Szrj df_analyze ();
697*38fd1498Szrj combine_stack_adjustments ();
698*38fd1498Szrj return 0;
699*38fd1498Szrj }
700*38fd1498Szrj
701*38fd1498Szrj namespace {
702*38fd1498Szrj
703*38fd1498Szrj const pass_data pass_data_stack_adjustments =
704*38fd1498Szrj {
705*38fd1498Szrj RTL_PASS, /* type */
706*38fd1498Szrj "csa", /* name */
707*38fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
708*38fd1498Szrj TV_COMBINE_STACK_ADJUST, /* tv_id */
709*38fd1498Szrj 0, /* properties_required */
710*38fd1498Szrj 0, /* properties_provided */
711*38fd1498Szrj 0, /* properties_destroyed */
712*38fd1498Szrj 0, /* todo_flags_start */
713*38fd1498Szrj TODO_df_finish, /* todo_flags_finish */
714*38fd1498Szrj };
715*38fd1498Szrj
716*38fd1498Szrj class pass_stack_adjustments : public rtl_opt_pass
717*38fd1498Szrj {
718*38fd1498Szrj public:
pass_stack_adjustments(gcc::context * ctxt)719*38fd1498Szrj pass_stack_adjustments (gcc::context *ctxt)
720*38fd1498Szrj : rtl_opt_pass (pass_data_stack_adjustments, ctxt)
721*38fd1498Szrj {}
722*38fd1498Szrj
723*38fd1498Szrj /* opt_pass methods: */
724*38fd1498Szrj virtual bool gate (function *);
execute(function *)725*38fd1498Szrj virtual unsigned int execute (function *)
726*38fd1498Szrj {
727*38fd1498Szrj return rest_of_handle_stack_adjustments ();
728*38fd1498Szrj }
729*38fd1498Szrj
730*38fd1498Szrj }; // class pass_stack_adjustments
731*38fd1498Szrj
732*38fd1498Szrj bool
gate(function *)733*38fd1498Szrj pass_stack_adjustments::gate (function *)
734*38fd1498Szrj {
735*38fd1498Szrj /* This is kind of a heuristic. We need to run combine_stack_adjustments
736*38fd1498Szrj even for machines with possibly nonzero TARGET_RETURN_POPS_ARGS
737*38fd1498Szrj and ACCUMULATE_OUTGOING_ARGS. We expect that only ports having
738*38fd1498Szrj push instructions will have popping returns. */
739*38fd1498Szrj #ifndef PUSH_ROUNDING
740*38fd1498Szrj if (ACCUMULATE_OUTGOING_ARGS)
741*38fd1498Szrj return false;
742*38fd1498Szrj #endif
743*38fd1498Szrj return flag_combine_stack_adjustments;
744*38fd1498Szrj }
745*38fd1498Szrj
746*38fd1498Szrj } // anon namespace
747*38fd1498Szrj
748*38fd1498Szrj rtl_opt_pass *
make_pass_stack_adjustments(gcc::context * ctxt)749*38fd1498Szrj make_pass_stack_adjustments (gcc::context *ctxt)
750*38fd1498Szrj {
751*38fd1498Szrj return new pass_stack_adjustments (ctxt);
752*38fd1498Szrj }
753