1 /* Lower and optimize address expressions.
2    Copyright (C) 2015-2018 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