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