1 /* Combine stack adjustments.
2    Copyright (C) 1987-2018 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
combine_stack_adjustments(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
stack_memref_p(rtx x)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
single_set_for_csa(rtx_insn * insn)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
free_csa_reflist(struct csa_reflist * reflist)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 *
record_one_stack_ref(rtx_insn * insn,rtx * ref,struct csa_reflist * next_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
no_unhandled_cfa(rtx_insn * insn)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
try_apply_stack_adjustment(rtx_insn * insn,struct csa_reflist * reflist,HOST_WIDE_INT new_adjust,HOST_WIDE_INT delta)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
record_stack_refs(rtx_insn * insn,struct csa_reflist ** reflist)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
maybe_move_args_size_note(rtx_insn * last,rtx_insn * insn,bool after)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
maybe_merge_cfa_adjust(rtx_insn * dst,rtx_insn * src,bool after)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 *
prev_active_insn_bb(basic_block bb,rtx_insn * 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 *
next_active_insn_bb(basic_block bb,rtx_insn * 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
force_move_args_size_note(basic_block bb,rtx_insn * prev,rtx_insn * insn)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
combine_stack_adjustments_for_block(basic_block bb)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 && find_reg_note (insn, REG_STACK_CHECK, NULL_RTX))
512 	set = NULL_RTX;
513       if (set)
514 	{
515 	  rtx dest = SET_DEST (set);
516 	  rtx src = SET_SRC (set);
517 
518 	  /* Find constant additions to the stack pointer.  */
519 	  if (dest == stack_pointer_rtx
520 	      && GET_CODE (src) == PLUS
521 	      && XEXP (src, 0) == stack_pointer_rtx
522 	      && CONST_INT_P (XEXP (src, 1)))
523 	    {
524 	      HOST_WIDE_INT this_adjust = INTVAL (XEXP (src, 1));
525 
526 	      /* If we've not seen an adjustment previously, record
527 		 it now and continue.  */
528 	      if (! last_sp_set)
529 		{
530 		  last_sp_set = insn;
531 		  last_sp_adjust = this_adjust;
532 		  continue;
533 		}
534 
535 	      /* If not all recorded refs can be adjusted, or the
536 		 adjustment is now too large for a constant addition,
537 		 we cannot merge the two stack adjustments.
538 
539 		 Also we need to be careful to not move stack pointer
540 		 such that we create stack accesses outside the allocated
541 		 area.  We can combine an allocation into the first insn,
542 		 or a deallocation into the second insn.  We can not
543 		 combine an allocation followed by a deallocation.
544 
545 		 The only somewhat frequent occurrence of the later is when
546 		 a function allocates a stack frame but does not use it.
547 		 For this case, we would need to analyze rtl stream to be
548 		 sure that allocated area is really unused.  This means not
549 		 only checking the memory references, but also all registers
550 		 or global memory references possibly containing a stack
551 		 frame address.
552 
553 		 Perhaps the best way to address this problem is to teach
554 		 gcc not to allocate stack for objects never used.  */
555 
556 	      /* Combine an allocation into the first instruction.  */
557 	      if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0)
558 		{
559 		  if (no_unhandled_cfa (insn)
560 		      && try_apply_stack_adjustment (last_sp_set, reflist,
561 						     last_sp_adjust
562 						     + this_adjust,
563 						     this_adjust))
564 		    {
565 		      /* It worked!  */
566 		      maybe_move_args_size_note (last_sp_set, insn, false);
567 		      maybe_merge_cfa_adjust (last_sp_set, insn, false);
568 		      delete_insn (insn);
569 		      last_sp_adjust += this_adjust;
570 		      continue;
571 		    }
572 		}
573 
574 	      /* Otherwise we have a deallocation.  Do not combine with
575 		 a previous allocation.  Combine into the second insn.  */
576 	      else if (STACK_GROWS_DOWNWARD
577 		       ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
578 		{
579 		  if (no_unhandled_cfa (last_sp_set)
580 		      && try_apply_stack_adjustment (insn, reflist,
581 						     last_sp_adjust
582 						     + this_adjust,
583 						     -last_sp_adjust))
584 		    {
585 		      /* It worked!  */
586 		      maybe_move_args_size_note (insn, last_sp_set, true);
587 		      maybe_merge_cfa_adjust (insn, last_sp_set, true);
588 		      delete_insn (last_sp_set);
589 		      last_sp_set = insn;
590 		      last_sp_adjust += this_adjust;
591 		      free_csa_reflist (reflist);
592 		      reflist = NULL;
593 		      continue;
594 		    }
595 		}
596 
597 	      /* Combination failed.  Restart processing from here.  If
598 		 deallocation+allocation conspired to cancel, we can
599 		 delete the old deallocation insn.  */
600 	      if (last_sp_set)
601 		{
602 		  if (last_sp_adjust == 0 && no_unhandled_cfa (last_sp_set))
603 		    {
604 		      maybe_move_args_size_note (insn, last_sp_set, true);
605 		      maybe_merge_cfa_adjust (insn, last_sp_set, true);
606 		      delete_insn (last_sp_set);
607 		    }
608 		  else
609 		    last2_sp_set = last_sp_set;
610 		}
611 	      free_csa_reflist (reflist);
612 	      reflist = NULL;
613 	      last_sp_set = insn;
614 	      last_sp_adjust = this_adjust;
615 	      continue;
616 	    }
617 
618 	  /* Find a store with pre-(dec|inc)rement or pre-modify of exactly
619 	     the previous adjustment and turn it into a simple store.  This
620 	     is equivalent to anticipating the stack adjustment so this must
621 	     be an allocation.  */
622 	  if (MEM_P (dest)
623 	      && ((STACK_GROWS_DOWNWARD
624 		   ? (GET_CODE (XEXP (dest, 0)) == PRE_DEC
625 		      && known_eq (last_sp_adjust,
626 				   GET_MODE_SIZE (GET_MODE (dest))))
627 		   : (GET_CODE (XEXP (dest, 0)) == PRE_INC
628 		      && known_eq (-last_sp_adjust,
629 				   GET_MODE_SIZE (GET_MODE (dest)))))
630 		  || ((STACK_GROWS_DOWNWARD
631 		       ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
632 		      && GET_CODE (XEXP (dest, 0)) == PRE_MODIFY
633 		      && GET_CODE (XEXP (XEXP (dest, 0), 1)) == PLUS
634 		      && XEXP (XEXP (XEXP (dest, 0), 1), 0)
635 			 == stack_pointer_rtx
636 		      && GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
637 		         == CONST_INT
638 		      && INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1))
639 		         == -last_sp_adjust))
640 	      && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
641 	      && !reg_mentioned_p (stack_pointer_rtx, src)
642 	      && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
643 	      && try_apply_stack_adjustment (insn, reflist, 0,
644 					     -last_sp_adjust))
645 	    {
646 	      if (last2_sp_set)
647 		maybe_move_args_size_note (last2_sp_set, last_sp_set, false);
648 	      else
649 	        maybe_move_args_size_note (insn, last_sp_set, true);
650 	      delete_insn (last_sp_set);
651 	      free_csa_reflist (reflist);
652 	      reflist = NULL;
653 	      last_sp_set = NULL;
654 	      last_sp_adjust = 0;
655 	      continue;
656 	    }
657 	}
658 
659       if (!CALL_P (insn) && last_sp_set
660 	  && record_stack_refs (insn, &reflist))
661 	continue;
662 
663       /* Otherwise, we were not able to process the instruction.
664 	 Do not continue collecting data across such a one.  */
665       if (last_sp_set
666 	  && (CALL_P (insn)
667 	      || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
668 	{
669 	  if (last_sp_set && last_sp_adjust == 0)
670 	    {
671 	      force_move_args_size_note (bb, last2_sp_set, last_sp_set);
672 	      delete_insn (last_sp_set);
673 	    }
674 	  free_csa_reflist (reflist);
675 	  reflist = NULL;
676 	  last2_sp_set = NULL;
677 	  last_sp_set = NULL;
678 	  last_sp_adjust = 0;
679 	}
680     }
681 
682   if (last_sp_set && last_sp_adjust == 0)
683     {
684       force_move_args_size_note (bb, last2_sp_set, last_sp_set);
685       delete_insn (last_sp_set);
686     }
687 
688   if (reflist)
689     free_csa_reflist (reflist);
690 }
691 
692 static unsigned int
rest_of_handle_stack_adjustments(void)693 rest_of_handle_stack_adjustments (void)
694 {
695   df_note_add_problem ();
696   df_analyze ();
697   combine_stack_adjustments ();
698   return 0;
699 }
700 
701 namespace {
702 
703 const pass_data pass_data_stack_adjustments =
704 {
705   RTL_PASS, /* type */
706   "csa", /* name */
707   OPTGROUP_NONE, /* optinfo_flags */
708   TV_COMBINE_STACK_ADJUST, /* tv_id */
709   0, /* properties_required */
710   0, /* properties_provided */
711   0, /* properties_destroyed */
712   0, /* todo_flags_start */
713   TODO_df_finish, /* todo_flags_finish */
714 };
715 
716 class pass_stack_adjustments : public rtl_opt_pass
717 {
718 public:
pass_stack_adjustments(gcc::context * ctxt)719   pass_stack_adjustments (gcc::context *ctxt)
720     : rtl_opt_pass (pass_data_stack_adjustments, ctxt)
721   {}
722 
723   /* opt_pass methods: */
724   virtual bool gate (function *);
execute(function *)725   virtual unsigned int execute (function *)
726     {
727       return rest_of_handle_stack_adjustments ();
728     }
729 
730 }; // class pass_stack_adjustments
731 
732 bool
gate(function *)733 pass_stack_adjustments::gate (function *)
734 {
735   /* This is kind of a heuristic.  We need to run combine_stack_adjustments
736      even for machines with possibly nonzero TARGET_RETURN_POPS_ARGS
737      and ACCUMULATE_OUTGOING_ARGS.  We expect that only ports having
738      push instructions will have popping returns.  */
739 #ifndef PUSH_ROUNDING
740   if (ACCUMULATE_OUTGOING_ARGS)
741     return false;
742 #endif
743   return flag_combine_stack_adjustments;
744 }
745 
746 } // anon namespace
747 
748 rtl_opt_pass *
make_pass_stack_adjustments(gcc::context * ctxt)749 make_pass_stack_adjustments (gcc::context *ctxt)
750 {
751   return new pass_stack_adjustments (ctxt);
752 }
753