/* Lower and optimize address expressions. Copyright (C) 2015-2024 Free Software Foundation, Inc. Contributed by Marek Polacek 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 . */ #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); }