blob: 11754dac5c38d7edbc8afb10795d6dca158840b0 [file] [log] [blame]
/* Lower and optimize address expressions.
Copyright (C) 2015-2022 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 () final override { return new pass_laddress (m_ctxt); }
bool gate (function *) final override { return optimize != 0; }
unsigned int execute (function *) final override;
}; // 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);
poly_int64 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);
poly_int64 bytepos = exact_div (bitpos, BITS_PER_UNIT);
if (offset != NULL_TREE)
{
if (maybe_ne (bytepos, 0))
offset = size_binop (PLUS_EXPR, offset, size_int (bytepos));
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);
}