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