163aace61Smrg /* Lower and optimize address expressions.
2*dd083157Smrg    Copyright (C) 2015-2020 Free Software Foundation, Inc.
363aace61Smrg    Contributed by Marek Polacek <polacek@redhat.com>
463aace61Smrg 
563aace61Smrg This file is part of GCC.
663aace61Smrg 
763aace61Smrg GCC is free software; you can redistribute it and/or modify it under
863aace61Smrg the terms of the GNU General Public License as published by the Free
963aace61Smrg Software Foundation; either version 3, or (at your option) any later
1063aace61Smrg version.
1163aace61Smrg 
1263aace61Smrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1363aace61Smrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
1463aace61Smrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1563aace61Smrg for more details.
1663aace61Smrg 
1763aace61Smrg You should have received a copy of the GNU General Public License
1863aace61Smrg along with GCC; see the file COPYING3.  If not see
1963aace61Smrg <http://www.gnu.org/licenses/>.  */
2063aace61Smrg 
2163aace61Smrg #include "config.h"
2263aace61Smrg #include "system.h"
2363aace61Smrg #include "coretypes.h"
2463aace61Smrg #include "alias.h"
2563aace61Smrg #include "predict.h"
2663aace61Smrg #include "tm.h"
2763aace61Smrg #include "function.h"
2863aace61Smrg #include "dominance.h"
2963aace61Smrg #include "cfg.h"
3063aace61Smrg #include "basic-block.h"
3163aace61Smrg #include "tree-ssa-alias.h"
3263aace61Smrg #include "symtab.h"
3363aace61Smrg #include "tree.h"
3463aace61Smrg #include "stringpool.h"
356a5c9aabSmrg #include "tree-vrp.h"
3663aace61Smrg #include "tree-ssanames.h"
3763aace61Smrg #include "fold-const.h"
3863aace61Smrg #include "gimple-expr.h"
3963aace61Smrg #include "gimple.h"
4063aace61Smrg #include "gimplify.h"
4163aace61Smrg #include "gimple-iterator.h"
4263aace61Smrg #include "gimplify-me.h"
4363aace61Smrg #include "tree-pass.h"
4463aace61Smrg 
4563aace61Smrg 
4663aace61Smrg namespace {
4763aace61Smrg 
4863aace61Smrg const pass_data pass_data_laddress =
4963aace61Smrg {
5063aace61Smrg   GIMPLE_PASS, /* type */
5163aace61Smrg   "laddress", /* name */
5263aace61Smrg   OPTGROUP_NONE, /* optinfo_flags */
5363aace61Smrg   TV_GIMPLE_LADDRESS, /* tv_id */
5463aace61Smrg   ( PROP_cfg | PROP_ssa ), /* properties_required */
5563aace61Smrg   0, /* properties_provided */
5663aace61Smrg   0, /* properties_destroyed */
5763aace61Smrg   0, /* todo_flags_start */
5863aace61Smrg   0, /* todo_flags_finish */
5963aace61Smrg };
6063aace61Smrg 
6163aace61Smrg class pass_laddress : public gimple_opt_pass
6263aace61Smrg {
6363aace61Smrg public:
pass_laddress(gcc::context * ctxt)6463aace61Smrg   pass_laddress (gcc::context *ctxt)
6563aace61Smrg     : gimple_opt_pass (pass_data_laddress, ctxt)
6663aace61Smrg   {}
6763aace61Smrg 
6863aace61Smrg   /* opt_pass methods: */
clone()6963aace61Smrg   opt_pass * clone () { return new pass_laddress (m_ctxt); }
gate(function *)7063aace61Smrg   virtual bool gate (function *) { return optimize != 0; }
7163aace61Smrg   virtual unsigned int execute (function *);
7263aace61Smrg 
7363aace61Smrg }; // class pass_laddress
7463aace61Smrg 
7563aace61Smrg unsigned int
execute(function * fun)7663aace61Smrg pass_laddress::execute (function *fun)
7763aace61Smrg {
7863aace61Smrg   basic_block bb;
7963aace61Smrg 
8063aace61Smrg   FOR_EACH_BB_FN (bb, fun)
8163aace61Smrg     {
8263aace61Smrg       for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
8363aace61Smrg 	{
8463aace61Smrg 	  gimple *stmt = gsi_stmt (gsi);
8563aace61Smrg 	  if (!is_gimple_assign (stmt)
8663aace61Smrg 	      || gimple_assign_rhs_code (stmt) != ADDR_EXPR
8763aace61Smrg 	      || is_gimple_invariant_address (gimple_assign_rhs1 (stmt)))
8863aace61Smrg 	    {
8963aace61Smrg 	      gsi_next (&gsi);
9063aace61Smrg 	      continue;
9163aace61Smrg 	    }
9263aace61Smrg 
9363aace61Smrg 	  /* Lower ADDR_EXPR assignments:
9463aace61Smrg 	       _4 = &b[i_9];
9563aace61Smrg 	     into
9663aace61Smrg 	       _1 = (sizetype) i_9;
9763aace61Smrg 	       _7 = _1 * 4;
9863aace61Smrg 	       _4 = &b + _7;
9963aace61Smrg 	     This ought to aid the vectorizer and expose CSE opportunities.
10063aace61Smrg 	  */
10163aace61Smrg 
10263aace61Smrg 	  tree expr = gimple_assign_rhs1 (stmt);
1033903d7f3Smrg 	  poly_int64 bitsize, bitpos;
10463aace61Smrg 	  tree base, offset;
10563aace61Smrg 	  machine_mode mode;
10663aace61Smrg 	  int volatilep = 0, reversep, unsignedp = 0;
10763aace61Smrg 	  base = get_inner_reference (TREE_OPERAND (expr, 0), &bitsize,
10863aace61Smrg 				      &bitpos, &offset, &mode, &unsignedp,
1096a5c9aabSmrg 				      &reversep, &volatilep);
1103903d7f3Smrg 	  gcc_assert (base != NULL_TREE);
1113903d7f3Smrg 	  poly_int64 bytepos = exact_div (bitpos, BITS_PER_UNIT);
11263aace61Smrg 	  if (offset != NULL_TREE)
11363aace61Smrg 	    {
1143903d7f3Smrg 	      if (maybe_ne (bytepos, 0))
1153903d7f3Smrg 		offset = size_binop (PLUS_EXPR, offset, size_int (bytepos));
11663aace61Smrg 	      offset = force_gimple_operand_gsi (&gsi, offset, true, NULL,
11763aace61Smrg 						 true, GSI_SAME_STMT);
11863aace61Smrg 	      base = build_fold_addr_expr (base);
11963aace61Smrg 	      base = force_gimple_operand_gsi (&gsi, base, true, NULL,
12063aace61Smrg 					       true, GSI_SAME_STMT);
12163aace61Smrg 	      gimple *g = gimple_build_assign (gimple_assign_lhs (stmt),
12263aace61Smrg 					      POINTER_PLUS_EXPR, base, offset);
12363aace61Smrg 	      gsi_replace (&gsi, g, false);
12463aace61Smrg 	    }
12563aace61Smrg 	  gsi_next (&gsi);
12663aace61Smrg 	}
12763aace61Smrg     }
12863aace61Smrg 
12963aace61Smrg   return 0;
13063aace61Smrg }
13163aace61Smrg 
13263aace61Smrg } // anon namespace
13363aace61Smrg 
13463aace61Smrg gimple_opt_pass *
make_pass_laddress(gcc::context * ctxt)13563aace61Smrg make_pass_laddress (gcc::context *ctxt)
13663aace61Smrg {
13763aace61Smrg   return new pass_laddress (ctxt);
13863aace61Smrg }
139