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