1 /* Lower and optimize address expressions.
2    Copyright (C) 2015-2022 Free Software Foundation, Inc.
3    Contributed by Marek Polacek <polacek@redhat.com>
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11 
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20 
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "alias.h"
25 #include "predict.h"
26 #include "tm.h"
27 #include "function.h"
28 #include "dominance.h"
29 #include "cfg.h"
30 #include "basic-block.h"
31 #include "tree-ssa-alias.h"
32 #include "symtab.h"
33 #include "tree.h"
34 #include "stringpool.h"
35 #include "tree-vrp.h"
36 #include "tree-ssanames.h"
37 #include "fold-const.h"
38 #include "gimple-expr.h"
39 #include "gimple.h"
40 #include "gimplify.h"
41 #include "gimple-iterator.h"
42 #include "gimplify-me.h"
43 #include "tree-pass.h"
44 
45 
46 namespace {
47 
48 const pass_data pass_data_laddress =
49 {
50   GIMPLE_PASS, /* type */
51   "laddress", /* name */
52   OPTGROUP_NONE, /* optinfo_flags */
53   TV_GIMPLE_LADDRESS, /* tv_id */
54   ( PROP_cfg | PROP_ssa ), /* properties_required */
55   0, /* properties_provided */
56   0, /* properties_destroyed */
57   0, /* todo_flags_start */
58   0, /* todo_flags_finish */
59 };
60 
61 class pass_laddress : public gimple_opt_pass
62 {
63 public:
pass_laddress(gcc::context * ctxt)64   pass_laddress (gcc::context *ctxt)
65     : gimple_opt_pass (pass_data_laddress, ctxt)
66   {}
67 
68   /* opt_pass methods: */
clone()69   opt_pass * clone () { return new pass_laddress (m_ctxt); }
gate(function *)70   virtual bool gate (function *) { return optimize != 0; }
71   virtual unsigned int execute (function *);
72 
73 }; // class pass_laddress
74 
75 unsigned int
execute(function * fun)76 pass_laddress::execute (function *fun)
77 {
78   basic_block bb;
79 
80   FOR_EACH_BB_FN (bb, fun)
81     {
82       for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
83           {
84             gimple *stmt = gsi_stmt (gsi);
85             if (!is_gimple_assign (stmt)
86                 || gimple_assign_rhs_code (stmt) != ADDR_EXPR
87                 || is_gimple_invariant_address (gimple_assign_rhs1 (stmt)))
88               {
89                 gsi_next (&gsi);
90                 continue;
91               }
92 
93             /* Lower ADDR_EXPR assignments:
94                  _4 = &b[i_9];
95                into
96                  _1 = (sizetype) i_9;
97                  _7 = _1 * 4;
98                  _4 = &b + _7;
99                This ought to aid the vectorizer and expose CSE opportunities.
100             */
101 
102             tree expr = gimple_assign_rhs1 (stmt);
103             poly_int64 bitsize, bitpos;
104             tree base, offset;
105             machine_mode mode;
106             int volatilep = 0, reversep, unsignedp = 0;
107             base = get_inner_reference (TREE_OPERAND (expr, 0), &bitsize,
108                                               &bitpos, &offset, &mode, &unsignedp,
109                                               &reversep, &volatilep);
110             gcc_assert (base != NULL_TREE);
111             poly_int64 bytepos = exact_div (bitpos, BITS_PER_UNIT);
112             if (offset != NULL_TREE)
113               {
114                 if (maybe_ne (bytepos, 0))
115                     offset = size_binop (PLUS_EXPR, offset, size_int (bytepos));
116                 offset = force_gimple_operand_gsi (&gsi, offset, true, NULL,
117                                                              true, GSI_SAME_STMT);
118                 base = build_fold_addr_expr (base);
119                 base = force_gimple_operand_gsi (&gsi, base, true, NULL,
120                                                          true, GSI_SAME_STMT);
121                 gimple *g = gimple_build_assign (gimple_assign_lhs (stmt),
122                                                         POINTER_PLUS_EXPR, base, offset);
123                 gsi_replace (&gsi, g, false);
124               }
125             gsi_next (&gsi);
126           }
127     }
128 
129   return 0;
130 }
131 
132 } // anon namespace
133 
134 gimple_opt_pass *
make_pass_laddress(gcc::context * ctxt)135 make_pass_laddress (gcc::context *ctxt)
136 {
137   return new pass_laddress (ctxt);
138 }
139