1230479Snetchild/* Combine stack adjustments.
2230479Snetchild   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
3230479Snetchild   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
4230479Snetchild   Free Software Foundation, Inc.
5230479Snetchild
6230479SnetchildThis file is part of GCC.
7230479Snetchild
8230479SnetchildGCC is free software; you can redistribute it and/or modify it under
9230479Snetchildthe terms of the GNU General Public License as published by the Free
10230479SnetchildSoftware Foundation; either version 3, or (at your option) any later
11230479Snetchildversion.
12230479Snetchild
13230479SnetchildGCC is distributed in the hope that it will be useful, but WITHOUT ANY
14230479SnetchildWARRANTY; without even the implied warranty of MERCHANTABILITY or
15230479SnetchildFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16230479Snetchildfor more details.
17230479Snetchild
18230479SnetchildYou should have received a copy of the GNU General Public License
19230479Snetchildalong with GCC; see the file COPYING3.  If not see
20230479Snetchild<http://www.gnu.org/licenses/>.  */
21230479Snetchild
22/* Track stack adjustments and stack memory references.  Attempt to
23   reduce the number of stack adjustments by back-propagating across
24   the memory references.
25
26   This is intended primarily for use with targets that do not define
27   ACCUMULATE_OUTGOING_ARGS.  It is of significantly more value to
28   targets that define PREFERRED_STACK_BOUNDARY more aligned than
29   STACK_BOUNDARY (e.g. x86), or if not all registers can be pushed
30   (e.g. x86 fp regs) which would ordinarily have to be implemented
31   as a sub/mov pair due to restrictions in calls.c.
32
33   Propagation stops when any of the insns that need adjusting are
34   (a) no longer valid because we've exceeded their range, (b) a
35   non-trivial push instruction, or (c) a call instruction.
36
37   Restriction B is based on the assumption that push instructions
38   are smaller or faster.  If a port really wants to remove all
39   pushes, it should have defined ACCUMULATE_OUTGOING_ARGS.  The
40   one exception that is made is for an add immediately followed
41   by a push.  */
42
43#include "config.h"
44#include "system.h"
45#include "coretypes.h"
46#include "tm.h"
47#include "rtl.h"
48#include "tm_p.h"
49#include "insn-config.h"
50#include "recog.h"
51#include "output.h"
52#include "regs.h"
53#include "hard-reg-set.h"
54#include "flags.h"
55#include "function.h"
56#include "expr.h"
57#include "basic-block.h"
58#include "df.h"
59#include "except.h"
60#include "toplev.h"
61#include "reload.h"
62#include "timevar.h"
63#include "tree-pass.h"
64
65
66/* Turn STACK_GROWS_DOWNWARD into a boolean.  */
67#ifdef STACK_GROWS_DOWNWARD
68#undef STACK_GROWS_DOWNWARD
69#define STACK_GROWS_DOWNWARD 1
70#else
71#define STACK_GROWS_DOWNWARD 0
72#endif
73
74/* This structure records two kinds of stack references between stack
75   adjusting instructions: stack references in memory addresses for
76   regular insns and all stack references for debug insns.  */
77
78struct csa_reflist
79{
80  HOST_WIDE_INT sp_offset;
81  rtx insn, *ref;
82  struct csa_reflist *next;
83};
84
85static int stack_memref_p (rtx);
86static rtx single_set_for_csa (rtx);
87static void free_csa_reflist (struct csa_reflist *);
88static struct csa_reflist *record_one_stack_ref (rtx, rtx *,
89						 struct csa_reflist *);
90static int try_apply_stack_adjustment (rtx, struct csa_reflist *,
91				       HOST_WIDE_INT, HOST_WIDE_INT);
92static void combine_stack_adjustments_for_block (basic_block);
93static int record_stack_refs (rtx *, void *);
94
95
96/* Main entry point for stack adjustment combination.  */
97
98static void
99combine_stack_adjustments (void)
100{
101  basic_block bb;
102
103  FOR_EACH_BB (bb)
104    combine_stack_adjustments_for_block (bb);
105}
106
107/* Recognize a MEM of the form (sp) or (plus sp const).  */
108
109static int
110stack_memref_p (rtx x)
111{
112  if (!MEM_P (x))
113    return 0;
114  x = XEXP (x, 0);
115
116  if (x == stack_pointer_rtx)
117    return 1;
118  if (GET_CODE (x) == PLUS
119      && XEXP (x, 0) == stack_pointer_rtx
120      && CONST_INT_P (XEXP (x, 1)))
121    return 1;
122
123  return 0;
124}
125
126/* Recognize either normal single_set or the hack in i386.md for
127   tying fp and sp adjustments.  */
128
129static rtx
130single_set_for_csa (rtx insn)
131{
132  int i;
133  rtx tmp = single_set (insn);
134  if (tmp)
135    return tmp;
136
137  if (!NONJUMP_INSN_P (insn)
138      || GET_CODE (PATTERN (insn)) != PARALLEL)
139    return NULL_RTX;
140
141  tmp = PATTERN (insn);
142  if (GET_CODE (XVECEXP (tmp, 0, 0)) != SET)
143    return NULL_RTX;
144
145  for (i = 1; i < XVECLEN (tmp, 0); ++i)
146    {
147      rtx this_rtx = XVECEXP (tmp, 0, i);
148
149      /* The special case is allowing a no-op set.  */
150      if (GET_CODE (this_rtx) == SET
151	  && SET_SRC (this_rtx) == SET_DEST (this_rtx))
152	;
153      else if (GET_CODE (this_rtx) != CLOBBER
154	       && GET_CODE (this_rtx) != USE)
155	return NULL_RTX;
156    }
157
158  return XVECEXP (tmp, 0, 0);
159}
160
161/* Free the list of csa_reflist nodes.  */
162
163static void
164free_csa_reflist (struct csa_reflist *reflist)
165{
166  struct csa_reflist *next;
167  for (; reflist ; reflist = next)
168    {
169      next = reflist->next;
170      free (reflist);
171    }
172}
173
174/* Create a new csa_reflist node from the given stack reference.
175   It is already known that the reference is either a MEM satisfying the
176   predicate stack_memref_p or a REG representing the stack pointer.  */
177
178static struct csa_reflist *
179record_one_stack_ref (rtx insn, rtx *ref, struct csa_reflist *next_reflist)
180{
181  struct csa_reflist *ml;
182
183  ml = XNEW (struct csa_reflist);
184
185  if (REG_P (*ref) || XEXP (*ref, 0) == stack_pointer_rtx)
186    ml->sp_offset = 0;
187  else
188    ml->sp_offset = INTVAL (XEXP (XEXP (*ref, 0), 1));
189
190  ml->insn = insn;
191  ml->ref = ref;
192  ml->next = next_reflist;
193
194  return ml;
195}
196
197/* Attempt to apply ADJUST to the stack adjusting insn INSN, as well
198   as each of the memories and stack references in REFLIST.  Return true
199   on success.  */
200
201static int
202try_apply_stack_adjustment (rtx insn, struct csa_reflist *reflist,
203			    HOST_WIDE_INT new_adjust, HOST_WIDE_INT delta)
204{
205  struct csa_reflist *ml;
206  rtx set;
207
208  set = single_set_for_csa (insn);
209  if (MEM_P (SET_DEST (set)))
210    validate_change (insn, &SET_DEST (set),
211		     replace_equiv_address (SET_DEST (set), stack_pointer_rtx),
212		     1);
213  else
214    validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust), 1);
215
216  for (ml = reflist; ml ; ml = ml->next)
217    {
218      rtx new_addr = plus_constant (stack_pointer_rtx, ml->sp_offset - delta);
219      rtx new_val;
220
221      if (MEM_P (*ml->ref))
222	new_val = replace_equiv_address_nv (*ml->ref, new_addr);
223      else if (GET_MODE (*ml->ref) == GET_MODE (stack_pointer_rtx))
224	new_val = new_addr;
225      else
226	new_val = lowpart_subreg (GET_MODE (*ml->ref), new_addr,
227				  GET_MODE (new_addr));
228      validate_change (ml->insn, ml->ref, new_val, 1);
229    }
230
231  if (apply_change_group ())
232    {
233      /* Succeeded.  Update our knowledge of the stack references.  */
234      for (ml = reflist; ml ; ml = ml->next)
235	ml->sp_offset -= delta;
236
237      return 1;
238    }
239  else
240    return 0;
241}
242
243/* Called via for_each_rtx and used to record all stack memory and other
244   references in the insn and discard all other stack pointer references.  */
245struct record_stack_refs_data
246{
247  rtx insn;
248  struct csa_reflist *reflist;
249};
250
251static int
252record_stack_refs (rtx *xp, void *data)
253{
254  rtx x = *xp;
255  struct record_stack_refs_data *d =
256    (struct record_stack_refs_data *) data;
257  if (!x)
258    return 0;
259  switch (GET_CODE (x))
260    {
261    case MEM:
262      if (!reg_mentioned_p (stack_pointer_rtx, x))
263	return -1;
264      /* We are not able to handle correctly all possible memrefs containing
265         stack pointer, so this check is necessary.  */
266      if (stack_memref_p (x))
267	{
268	  d->reflist = record_one_stack_ref (d->insn, xp, d->reflist);
269	  return -1;
270	}
271      /* Try harder for DEBUG_INSNs, handle e.g. (mem (mem (sp + 16) + 4).  */
272      return !DEBUG_INSN_P (d->insn);
273    case REG:
274      /* ??? We want be able to handle non-memory stack pointer
275	 references later.  For now just discard all insns referring to
276	 stack pointer outside mem expressions.  We would probably
277	 want to teach validate_replace to simplify expressions first.
278
279	 We can't just compare with STACK_POINTER_RTX because the
280	 reference to the stack pointer might be in some other mode.
281	 In particular, an explicit clobber in an asm statement will
282	 result in a QImode clobber.
283
284	 In DEBUG_INSNs, we want to replace all occurrences, otherwise
285	 they will cause -fcompare-debug failures.  */
286      if (REGNO (x) == STACK_POINTER_REGNUM)
287	{
288	  if (!DEBUG_INSN_P (d->insn))
289	    return 1;
290	  d->reflist = record_one_stack_ref (d->insn, xp, d->reflist);
291	  return -1;
292	}
293      break;
294    default:
295      break;
296    }
297  return 0;
298}
299
300/* Adjust or create REG_FRAME_RELATED_EXPR note when merging a stack
301   adjustment into a frame related insn.  */
302
303static void
304adjust_frame_related_expr (rtx last_sp_set, rtx insn,
305			   HOST_WIDE_INT this_adjust)
306{
307  rtx note = find_reg_note (last_sp_set, REG_FRAME_RELATED_EXPR, NULL_RTX);
308  rtx new_expr = NULL_RTX;
309
310  if (note == NULL_RTX && RTX_FRAME_RELATED_P (insn))
311    return;
312
313  if (note
314      && GET_CODE (XEXP (note, 0)) == SEQUENCE
315      && XVECLEN (XEXP (note, 0), 0) >= 2)
316    {
317      rtx expr = XEXP (note, 0);
318      rtx last = XVECEXP (expr, 0, XVECLEN (expr, 0) - 1);
319      int i;
320
321      if (GET_CODE (last) == SET
322	  && RTX_FRAME_RELATED_P (last) == RTX_FRAME_RELATED_P (insn)
323	  && SET_DEST (last) == stack_pointer_rtx
324	  && GET_CODE (SET_SRC (last)) == PLUS
325	  && XEXP (SET_SRC (last), 0) == stack_pointer_rtx
326	  && CONST_INT_P (XEXP (SET_SRC (last), 1)))
327	{
328	  XEXP (SET_SRC (last), 1)
329	    = GEN_INT (INTVAL (XEXP (SET_SRC (last), 1)) + this_adjust);
330	  return;
331	}
332
333      new_expr = gen_rtx_SEQUENCE (VOIDmode,
334				   rtvec_alloc (XVECLEN (expr, 0) + 1));
335      for (i = 0; i < XVECLEN (expr, 0); i++)
336	XVECEXP (new_expr, 0, i) = XVECEXP (expr, 0, i);
337    }
338  else
339    {
340      new_expr = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (2));
341      if (note)
342	XVECEXP (new_expr, 0, 0) = XEXP (note, 0);
343      else
344	{
345	  rtx expr = copy_rtx (single_set_for_csa (last_sp_set));
346
347	  XEXP (SET_SRC (expr), 1)
348	    = GEN_INT (INTVAL (XEXP (SET_SRC (expr), 1)) - this_adjust);
349	  RTX_FRAME_RELATED_P (expr) = 1;
350	  XVECEXP (new_expr, 0, 0) = expr;
351	}
352    }
353
354  XVECEXP (new_expr, 0, XVECLEN (new_expr, 0) - 1)
355    = copy_rtx (single_set_for_csa (insn));
356  RTX_FRAME_RELATED_P (XVECEXP (new_expr, 0, XVECLEN (new_expr, 0) - 1))
357    = RTX_FRAME_RELATED_P (insn);
358  if (note)
359    XEXP (note, 0) = new_expr;
360  else
361    add_reg_note (last_sp_set, REG_FRAME_RELATED_EXPR, new_expr);
362}
363
364/* Subroutine of combine_stack_adjustments, called for each basic block.  */
365
366static void
367combine_stack_adjustments_for_block (basic_block bb)
368{
369  HOST_WIDE_INT last_sp_adjust = 0;
370  rtx last_sp_set = NULL_RTX;
371  struct csa_reflist *reflist = NULL;
372  rtx insn, next, set;
373  struct record_stack_refs_data data;
374  bool end_of_block = false;
375
376  for (insn = BB_HEAD (bb); !end_of_block ; insn = next)
377    {
378      end_of_block = insn == BB_END (bb);
379      next = NEXT_INSN (insn);
380
381      if (! INSN_P (insn))
382	continue;
383
384      set = single_set_for_csa (insn);
385      if (set)
386	{
387	  rtx dest = SET_DEST (set);
388	  rtx src = SET_SRC (set);
389
390	  /* Find constant additions to the stack pointer.  */
391	  if (dest == stack_pointer_rtx
392	      && GET_CODE (src) == PLUS
393	      && XEXP (src, 0) == stack_pointer_rtx
394	      && CONST_INT_P (XEXP (src, 1)))
395	    {
396	      HOST_WIDE_INT this_adjust = INTVAL (XEXP (src, 1));
397
398	      /* If we've not seen an adjustment previously, record
399		 it now and continue.  */
400	      if (! last_sp_set)
401		{
402		  last_sp_set = insn;
403		  last_sp_adjust = this_adjust;
404		  continue;
405		}
406
407	      /* If not all recorded refs can be adjusted, or the
408		 adjustment is now too large for a constant addition,
409		 we cannot merge the two stack adjustments.
410
411		 Also we need to be careful to not move stack pointer
412		 such that we create stack accesses outside the allocated
413		 area.  We can combine an allocation into the first insn,
414		 or a deallocation into the second insn.  We can not
415		 combine an allocation followed by a deallocation.
416
417		 The only somewhat frequent occurrence of the later is when
418		 a function allocates a stack frame but does not use it.
419		 For this case, we would need to analyze rtl stream to be
420		 sure that allocated area is really unused.  This means not
421		 only checking the memory references, but also all registers
422		 or global memory references possibly containing a stack
423		 frame address.
424
425		 Perhaps the best way to address this problem is to teach
426		 gcc not to allocate stack for objects never used.  */
427
428	      /* Combine an allocation into the first instruction.  */
429	      if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0)
430		{
431		  if (try_apply_stack_adjustment (last_sp_set, reflist,
432						  last_sp_adjust + this_adjust,
433						  this_adjust))
434		    {
435		      if (RTX_FRAME_RELATED_P (last_sp_set))
436			adjust_frame_related_expr (last_sp_set, insn,
437						   this_adjust);
438		      /* It worked!  */
439		      delete_insn (insn);
440		      last_sp_adjust += this_adjust;
441		      continue;
442		    }
443		}
444
445	      /* Otherwise we have a deallocation.  Do not combine with
446		 a previous allocation.  Combine into the second insn.  */
447	      else if (STACK_GROWS_DOWNWARD
448		       ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
449		{
450		  if (try_apply_stack_adjustment (insn, reflist,
451						  last_sp_adjust + this_adjust,
452						  -last_sp_adjust))
453		    {
454		      /* It worked!  */
455		      delete_insn (last_sp_set);
456		      last_sp_set = insn;
457		      last_sp_adjust += this_adjust;
458		      free_csa_reflist (reflist);
459		      reflist = NULL;
460		      continue;
461		    }
462		}
463
464	      /* Combination failed.  Restart processing from here.  If
465		 deallocation+allocation conspired to cancel, we can
466		 delete the old deallocation insn.  */
467	      if (last_sp_set && last_sp_adjust == 0)
468		delete_insn (last_sp_set);
469	      free_csa_reflist (reflist);
470	      reflist = NULL;
471	      last_sp_set = insn;
472	      last_sp_adjust = this_adjust;
473	      continue;
474	    }
475
476	  /* Find a store with pre-(dec|inc)rement or pre-modify of exactly
477	     the previous adjustment and turn it into a simple store.  This
478	     is equivalent to anticipating the stack adjustment so this must
479	     be an allocation.  */
480	  if (MEM_P (dest)
481	      && ((STACK_GROWS_DOWNWARD
482		   ? (GET_CODE (XEXP (dest, 0)) == PRE_DEC
483		      && last_sp_adjust
484			 == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest)))
485		   : (GET_CODE (XEXP (dest, 0)) == PRE_INC
486		      && last_sp_adjust
487		         == -(HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest))))
488		  || ((STACK_GROWS_DOWNWARD
489		       ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
490		      && GET_CODE (XEXP (dest, 0)) == PRE_MODIFY
491		      && GET_CODE (XEXP (XEXP (dest, 0), 1)) == PLUS
492		      && XEXP (XEXP (XEXP (dest, 0), 1), 0)
493			 == stack_pointer_rtx
494		      && GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
495		         == CONST_INT
496		      && INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1))
497		         == -last_sp_adjust))
498	      && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
499	      && !reg_mentioned_p (stack_pointer_rtx, src)
500	      && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
501	      && try_apply_stack_adjustment (insn, reflist, 0,
502					     -last_sp_adjust))
503	    {
504	      delete_insn (last_sp_set);
505	      free_csa_reflist (reflist);
506	      reflist = NULL;
507	      last_sp_set = NULL_RTX;
508	      last_sp_adjust = 0;
509	      continue;
510	    }
511	}
512
513      data.insn = insn;
514      data.reflist = reflist;
515      if (!CALL_P (insn) && last_sp_set
516	  && !for_each_rtx (&PATTERN (insn), record_stack_refs, &data))
517	{
518	   reflist = data.reflist;
519	   continue;
520	}
521      reflist = data.reflist;
522
523      /* Otherwise, we were not able to process the instruction.
524	 Do not continue collecting data across such a one.  */
525      if (last_sp_set
526	  && (CALL_P (insn)
527	      || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
528	{
529	  if (last_sp_set && last_sp_adjust == 0)
530	    delete_insn (last_sp_set);
531	  free_csa_reflist (reflist);
532	  reflist = NULL;
533	  last_sp_set = NULL_RTX;
534	  last_sp_adjust = 0;
535	}
536    }
537
538  if (last_sp_set && last_sp_adjust == 0)
539    delete_insn (last_sp_set);
540
541  if (reflist)
542    free_csa_reflist (reflist);
543}
544
545
546static bool
547gate_handle_stack_adjustments (void)
548{
549  return (optimize > 0);
550}
551
552static unsigned int
553rest_of_handle_stack_adjustments (void)
554{
555  cleanup_cfg (flag_crossjumping ? CLEANUP_CROSSJUMP : 0);
556
557  /* This is kind of a heuristic.  We need to run combine_stack_adjustments
558     even for machines with possibly nonzero RETURN_POPS_ARGS
559     and ACCUMULATE_OUTGOING_ARGS.  We expect that only ports having
560     push instructions will have popping returns.  */
561#ifndef PUSH_ROUNDING
562  if (!ACCUMULATE_OUTGOING_ARGS)
563#endif
564    {
565      df_note_add_problem ();
566      df_analyze ();
567      combine_stack_adjustments ();
568    }
569  return 0;
570}
571
572struct rtl_opt_pass pass_stack_adjustments =
573{
574 {
575  RTL_PASS,
576  "csa",                                /* name */
577  gate_handle_stack_adjustments,        /* gate */
578  rest_of_handle_stack_adjustments,     /* execute */
579  NULL,                                 /* sub */
580  NULL,                                 /* next */
581  0,                                    /* static_pass_number */
582  TV_COMBINE_STACK_ADJUST,              /* tv_id */
583  0,                                    /* properties_required */
584  0,                                    /* properties_provided */
585  0,                                    /* properties_destroyed */
586  0,                                    /* todo_flags_start */
587  TODO_df_finish | TODO_verify_rtl_sharing |
588  TODO_dump_func |
589  TODO_ggc_collect,                     /* todo_flags_finish */
590 }
591};
592