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