| /* Lower and optimize address expressions. |
| Copyright (C) 2015-2017 Free Software Foundation, Inc. |
| Contributed by Marek Polacek <polacek@redhat.com> |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "alias.h" |
| #include "predict.h" |
| #include "tm.h" |
| #include "function.h" |
| #include "dominance.h" |
| #include "cfg.h" |
| #include "basic-block.h" |
| #include "tree-ssa-alias.h" |
| #include "symtab.h" |
| #include "tree.h" |
| #include "stringpool.h" |
| #include "tree-vrp.h" |
| #include "tree-ssanames.h" |
| #include "fold-const.h" |
| #include "gimple-expr.h" |
| #include "gimple.h" |
| #include "gimplify.h" |
| #include "gimple-iterator.h" |
| #include "gimplify-me.h" |
| #include "tree-pass.h" |
| |
| |
| namespace { |
| |
| const pass_data pass_data_laddress = |
| { |
| GIMPLE_PASS, /* type */ |
| "laddress", /* name */ |
| OPTGROUP_NONE, /* optinfo_flags */ |
| TV_GIMPLE_LADDRESS, /* tv_id */ |
| ( PROP_cfg | PROP_ssa ), /* properties_required */ |
| 0, /* properties_provided */ |
| 0, /* properties_destroyed */ |
| 0, /* todo_flags_start */ |
| 0, /* todo_flags_finish */ |
| }; |
| |
| class pass_laddress : public gimple_opt_pass |
| { |
| public: |
| pass_laddress (gcc::context *ctxt) |
| : gimple_opt_pass (pass_data_laddress, ctxt) |
| {} |
| |
| /* opt_pass methods: */ |
| opt_pass * clone () { return new pass_laddress (m_ctxt); } |
| virtual bool gate (function *) { return optimize != 0; } |
| virtual unsigned int execute (function *); |
| |
| }; // class pass_laddress |
| |
| unsigned int |
| pass_laddress::execute (function *fun) |
| { |
| basic_block bb; |
| |
| FOR_EACH_BB_FN (bb, fun) |
| { |
| for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);) |
| { |
| gimple *stmt = gsi_stmt (gsi); |
| if (!is_gimple_assign (stmt) |
| || gimple_assign_rhs_code (stmt) != ADDR_EXPR |
| || is_gimple_invariant_address (gimple_assign_rhs1 (stmt))) |
| { |
| gsi_next (&gsi); |
| continue; |
| } |
| |
| /* Lower ADDR_EXPR assignments: |
| _4 = &b[i_9]; |
| into |
| _1 = (sizetype) i_9; |
| _7 = _1 * 4; |
| _4 = &b + _7; |
| This ought to aid the vectorizer and expose CSE opportunities. |
| */ |
| |
| tree expr = gimple_assign_rhs1 (stmt); |
| HOST_WIDE_INT bitsize, bitpos; |
| tree base, offset; |
| machine_mode mode; |
| int volatilep = 0, reversep, unsignedp = 0; |
| base = get_inner_reference (TREE_OPERAND (expr, 0), &bitsize, |
| &bitpos, &offset, &mode, &unsignedp, |
| &reversep, &volatilep); |
| gcc_assert (base != NULL_TREE && (bitpos % BITS_PER_UNIT) == 0); |
| if (offset != NULL_TREE) |
| { |
| if (bitpos != 0) |
| offset = size_binop (PLUS_EXPR, offset, |
| size_int (bitpos / BITS_PER_UNIT)); |
| offset = force_gimple_operand_gsi (&gsi, offset, true, NULL, |
| true, GSI_SAME_STMT); |
| base = build_fold_addr_expr (base); |
| base = force_gimple_operand_gsi (&gsi, base, true, NULL, |
| true, GSI_SAME_STMT); |
| gimple *g = gimple_build_assign (gimple_assign_lhs (stmt), |
| POINTER_PLUS_EXPR, base, offset); |
| gsi_replace (&gsi, g, false); |
| } |
| gsi_next (&gsi); |
| } |
| } |
| |
| return 0; |
| } |
| |
| } // anon namespace |
| |
| gimple_opt_pass * |
| make_pass_laddress (gcc::context *ctxt) |
| { |
| return new pass_laddress (ctxt); |
| } |