1/* Discover if the stack pointer is modified in a function.
2   Copyright (C) 2007-2015 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING3.  If not see
18<http://www.gnu.org/licenses/>.  */
19
20#include "config.h"
21#include "system.h"
22#include "coretypes.h"
23#include "tm.h"
24#include "hash-set.h"
25#include "machmode.h"
26#include "vec.h"
27#include "double-int.h"
28#include "input.h"
29#include "alias.h"
30#include "symtab.h"
31#include "wide-int.h"
32#include "inchash.h"
33#include "tree.h"
34#include "rtl.h"
35#include "regs.h"
36#include "hashtab.h"
37#include "hard-reg-set.h"
38#include "function.h"
39#include "flags.h"
40#include "statistics.h"
41#include "real.h"
42#include "fixed-value.h"
43#include "insn-config.h"
44#include "expmed.h"
45#include "dojump.h"
46#include "explow.h"
47#include "calls.h"
48#include "emit-rtl.h"
49#include "varasm.h"
50#include "stmt.h"
51#include "expr.h"
52#include "tree-pass.h"
53#include "predict.h"
54#include "dominance.h"
55#include "cfg.h"
56#include "basic-block.h"
57#include "output.h"
58#include "df.h"
59
60/* Determine if the stack pointer is constant over the life of the function.
61   Only useful before prologues have been emitted.  */
62
63static void
64notice_stack_pointer_modification_1 (rtx x, const_rtx pat ATTRIBUTE_UNUSED,
65				     void *data ATTRIBUTE_UNUSED)
66{
67  if (x == stack_pointer_rtx
68      /* The stack pointer is only modified indirectly as the result
69	 of a push until later.  See the comments in rtl.texi
70	 regarding Embedded Side-Effects on Addresses.  */
71      || (MEM_P (x)
72	  && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == RTX_AUTOINC
73	  && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx))
74    crtl->sp_is_unchanging = 0;
75}
76
77  /* Some targets can emit simpler epilogues if they know that sp was
78     not ever modified during the function.  After reload, of course,
79     we've already emitted the epilogue so there's no sense searching.  */
80
81namespace {
82
83const pass_data pass_data_stack_ptr_mod =
84{
85  RTL_PASS, /* type */
86  "*stack_ptr_mod", /* name */
87  OPTGROUP_NONE, /* optinfo_flags */
88  TV_NONE, /* tv_id */
89  0, /* properties_required */
90  0, /* properties_provided */
91  0, /* properties_destroyed */
92  0, /* todo_flags_start */
93  0, /* todo_flags_finish */
94};
95
96class pass_stack_ptr_mod : public rtl_opt_pass
97{
98public:
99  pass_stack_ptr_mod (gcc::context *ctxt)
100    : rtl_opt_pass (pass_data_stack_ptr_mod, ctxt)
101  {}
102
103  /* opt_pass methods: */
104  virtual unsigned int execute (function *);
105
106}; // class pass_stack_ptr_mod
107
108unsigned int
109pass_stack_ptr_mod::execute (function *fun)
110{
111  basic_block bb;
112  rtx_insn *insn;
113
114  /* Assume that the stack pointer is unchanging if alloca hasn't
115     been used.  */
116  crtl->sp_is_unchanging = !fun->calls_alloca;
117  if (crtl->sp_is_unchanging)
118    FOR_EACH_BB_FN (bb, fun)
119      FOR_BB_INSNS (bb, insn)
120        {
121	  if (INSN_P (insn))
122	    {
123	      /* Check if insn modifies the stack pointer.  */
124	      note_stores (PATTERN (insn),
125			   notice_stack_pointer_modification_1,
126			   NULL);
127	      if (! crtl->sp_is_unchanging)
128		return 0;
129	    }
130	}
131
132  /* The value coming into this pass was 0, and the exit block uses
133     are based on this.  If the value is now 1, we need to redo the
134     exit block uses.  */
135  if (df && crtl->sp_is_unchanging)
136    df_update_exit_block_uses ();
137
138  return 0;
139}
140
141} // anon namespace
142
143rtl_opt_pass *
144make_pass_stack_ptr_mod (gcc::context *ctxt)
145{
146  return new pass_stack_ptr_mod (ctxt);
147}
148