From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7810) id 2C7A83858D3C; Fri, 24 Nov 2023 10:58:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2C7A83858D3C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1700823501; bh=g6yvkU0AshuYzu4sZ4wxPYxpibsicjWGs9pQJAP36SY=; h=From:To:Subject:Date:From; b=hDOmlv+IJ9tK4l3EQmRvndFmN+Hf5SYlyMzEFJS8nCNpzhrO7WHJq+lcYAp6f4M+G MtX1D0kNZjXkm/A5W4AH6N/7+QQt/Xje3T234Pjqe0SUoJsOKdkmTcp94YTfWqdpJj LEeP82l1jasnTZskylkpM5V/SL7S4euhxogM2pJY= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Alex Coplan To: gcc-cvs@gcc.gnu.org Subject: [gcc r14-5820] rtl-ssa: Support for inserting new insns X-Act-Checkin: gcc X-Git-Author: Alex Coplan X-Git-Refname: refs/heads/master X-Git-Oldrev: eebcad0ac22010fc59de9d856bb02017fccab282 X-Git-Newrev: a49befbd2c783e751dc2110b544fe540eb7e33eb Message-Id: <20231124105821.2C7A83858D3C@sourceware.org> Date: Fri, 24 Nov 2023 10:58:21 +0000 (GMT) List-Id: https://gcc.gnu.org/g:a49befbd2c783e751dc2110b544fe540eb7e33eb commit r14-5820-ga49befbd2c783e751dc2110b544fe540eb7e33eb Author: Alex Coplan Date: Sat Sep 16 09:23:52 2023 +0100 rtl-ssa: Support for inserting new insns The upcoming aarch64 load pair pass needs to form store pairs, and can re-order stores over loads when alias analysis determines this is safe. In the case that both mem defs have uses in the RTL-SSA IR, and both stores require re-ordering over their uses, we represent that as (tentative) deletion of the original store insns and creation of a new insn, to prevent requiring repeated re-parenting of uses during the pass. We then update all mem uses that require re-parenting in one go at the end of the pass. To support this, RTL-SSA needs to handle inserting new insns (rather than just changing existing ones), so this patch adds support for that. New insns (and new accesses) are temporaries, allocated above a temporary obstack_watermark, such that the user can easily back out of a change without awkward bookkeeping. gcc/ChangeLog: * rtl-ssa/accesses.cc (function_info::create_set): New. * rtl-ssa/accesses.h (access_info::is_temporary): New. * rtl-ssa/changes.cc (move_insn): Handle new (temporary) insns. (function_info::finalize_new_accesses): Handle new/temporary user-created accesses. (function_info::apply_changes_to_insn): Ensure m_is_temp flag on new insns gets cleared. (function_info::change_insns): Handle new/temporary insns. (function_info::create_insn): New. * rtl-ssa/changes.h (class insn_change): Make function_info a friend class. * rtl-ssa/functions.h (function_info): Declare new entry points: create_set, create_insn. Declare new change_alloc helper. * rtl-ssa/insns.cc (insn_info::print_full): Identify temporary insns in dump. * rtl-ssa/insns.h (insn_info): Add new m_is_temp flag and accompanying is_temporary accessor. * rtl-ssa/internals.inl (insn_info::insn_info): Initialize m_is_temp to false. * rtl-ssa/member-fns.inl (function_info::change_alloc): New. * rtl-ssa/movement.h (restrict_movement_for_defs_ignoring): Add handling for temporary defs. Diff: --- gcc/rtl-ssa/accesses.cc | 10 ++++++ gcc/rtl-ssa/accesses.h | 4 +++ gcc/rtl-ssa/changes.cc | 86 ++++++++++++++++++++++++++++++++++++++++------ gcc/rtl-ssa/changes.h | 2 ++ gcc/rtl-ssa/functions.h | 14 ++++++++ gcc/rtl-ssa/insns.cc | 5 +++ gcc/rtl-ssa/insns.h | 7 +++- gcc/rtl-ssa/internals.inl | 1 + gcc/rtl-ssa/member-fns.inl | 12 +++++++ gcc/rtl-ssa/movement.h | 8 ++++- 10 files changed, 136 insertions(+), 13 deletions(-) diff --git a/gcc/rtl-ssa/accesses.cc b/gcc/rtl-ssa/accesses.cc index 510545a8bad..76d70fd8bd3 100644 --- a/gcc/rtl-ssa/accesses.cc +++ b/gcc/rtl-ssa/accesses.cc @@ -1456,6 +1456,16 @@ function_info::make_uses_available (obstack_watermark &watermark, return use_array (new_uses, num_uses); } +set_info * +function_info::create_set (obstack_watermark &watermark, + insn_info *insn, + resource_info resource) +{ + auto set = change_alloc (watermark, insn, resource); + set->m_is_temp = true; + return set; +} + // Return true if ACCESS1 can represent ACCESS2 and if ACCESS2 can // represent ACCESS1. static bool diff --git a/gcc/rtl-ssa/accesses.h b/gcc/rtl-ssa/accesses.h index fce31d46717..7e7a90ece97 100644 --- a/gcc/rtl-ssa/accesses.h +++ b/gcc/rtl-ssa/accesses.h @@ -204,6 +204,10 @@ public: // in the main instruction pattern. bool only_occurs_in_notes () const { return m_only_occurs_in_notes; } + // Return true if this is a temporary access, e.g. one created for + // an insn that is about to be inserted. + bool is_temporary () const { return m_is_temp; } + protected: access_info (resource_info, access_kind); diff --git a/gcc/rtl-ssa/changes.cc b/gcc/rtl-ssa/changes.cc index aab532b9f26..2f2d12d5f30 100644 --- a/gcc/rtl-ssa/changes.cc +++ b/gcc/rtl-ssa/changes.cc @@ -394,14 +394,20 @@ move_insn (insn_change &change, insn_info *after) // At the moment we don't support moving instructions between EBBs, // but this would be worth adding if it's useful. insn_info *insn = change.insn (); - gcc_assert (after->ebb () == insn->ebb ()); + bb_info *bb = after->bb (); basic_block cfg_bb = bb->cfg_bb (); - if (insn->bb () != bb) - // Force DF to mark the old block as dirty. - df_insn_delete (rtl); - ::remove_insn (rtl); + if (!insn->is_temporary ()) + { + gcc_assert (after->ebb () == insn->ebb ()); + + if (insn->bb () != bb) + // Force DF to mark the old block as dirty. + df_insn_delete (rtl); + ::remove_insn (rtl); + } + ::add_insn_after (rtl, after_rtl, cfg_bb); } @@ -437,12 +443,33 @@ function_info::finalize_new_accesses (insn_change &change, insn_info *pos) { def_info *def = find_access (change.new_defs, ref.regno); gcc_assert (def); + + if (def->m_is_temp && is_a (def) && def->last_def ()) + { + // For temporary sets being added with this change, we keep track of + // the corresponding permanent def using the last_def link. + // + // So if we have one of these, follow it to get the permanent def. + def = def->last_def (); + gcc_assert (!def->m_is_temp && !def->m_has_been_superceded); + } + if (def->m_is_temp) { - // At present, the only temporary instruction definitions we - // create are clobbers, such as those added during recog. - gcc_assert (is_a (def)); - def = allocate (change.insn (), ref.regno); + if (is_a (def)) + def = allocate (change.insn (), ref.regno); + else if (is_a (def)) + { + // Install the permanent set in the last_def link of the + // temporary def. This allows us to find the permanent def + // later in case we see a second write to the same resource. + def_info *perm_def = allocate (change.insn (), + def->resource ()); + def->set_last_def (perm_def); + def = perm_def; + } + else + gcc_unreachable (); } else if (!def->m_has_been_superceded) { @@ -645,6 +672,8 @@ function_info::apply_changes_to_insn (insn_change &change) insn->set_accesses (builder.finish ().begin (), num_defs, num_uses); } + + insn->m_is_temp = false; } // Add a temporary placeholder instruction after AFTER. @@ -677,7 +706,8 @@ function_info::change_insns (array_slice changes) if (!change->is_deletion ()) { // Remove any notes that are no longer relevant. - update_notes (change->rtl ()); + if (!change->insn ()->m_is_temp) + update_notes (change->rtl ()); // Make sure that the placement of this instruction would still // leave room for previous instructions. @@ -686,6 +716,17 @@ function_info::change_insns (array_slice changes) // verify_insn_changes is supposed to make sure that this holds. gcc_unreachable (); min_insn = later_insn (min_insn, change->move_range.first); + + if (change->insn ()->m_is_temp) + { + change->m_insn = allocate (change->insn ()->bb (), + change->rtl (), + change->insn_uid ()); + + // Set the flag again so subsequent logic is aware. + // It will be cleared later on. + change->m_insn->m_is_temp = true; + } } } @@ -784,7 +825,8 @@ function_info::change_insns (array_slice changes) // Remove the placeholder first so that we have a wider range of // program points when inserting INSN. insn_info *after = placeholder->prev_any_insn (); - remove_insn (insn); + if (!insn->is_temporary ()) + remove_insn (insn); remove_insn (placeholder); insn->set_bb (after->bb ()); add_insn_after (insn, after); @@ -1105,6 +1147,28 @@ function_info::perform_pending_updates () return changed_cfg; } +insn_info * +function_info::create_insn (obstack_watermark &watermark, + rtx_code insn_code, + rtx pat) +{ + rtx_insn *rti = nullptr; + + // TODO: extend, move in to emit-rtl.cc. + switch (insn_code) + { + case INSN: + rti = make_insn_raw (pat); + break; + default: + gcc_unreachable (); + } + + auto insn = change_alloc (watermark, nullptr, rti, INSN_UID (rti)); + insn->m_is_temp = true; + return insn; +} + // Print a description of CHANGE to PP. void rtl_ssa::pp_insn_change (pretty_printer *pp, const insn_change &change) diff --git a/gcc/rtl-ssa/changes.h b/gcc/rtl-ssa/changes.h index d56e3a646e2..d91cf432afe 100644 --- a/gcc/rtl-ssa/changes.h +++ b/gcc/rtl-ssa/changes.h @@ -32,6 +32,8 @@ namespace rtl_ssa { // something that we might do. class insn_change { + friend class function_info; + public: enum delete_action { DELETE }; diff --git a/gcc/rtl-ssa/functions.h b/gcc/rtl-ssa/functions.h index ecb40fdaf57..4ffd3fa44e2 100644 --- a/gcc/rtl-ssa/functions.h +++ b/gcc/rtl-ssa/functions.h @@ -68,6 +68,16 @@ public: // Return the SSA information for CFG_BB. bb_info *bb (basic_block cfg_bb) const { return m_bbs[cfg_bb->index]; } + // Create a temporary def. + set_info *create_set (obstack_watermark &watermark, + insn_info *insn, + resource_info resource); + + // Create a temporary insn with code INSN_CODE and pattern PAT. + insn_info *create_insn (obstack_watermark &watermark, + rtx_code insn_code, + rtx pat); + // Return a list of all the instructions in the function, in reverse // postorder. The list includes both real and artificial instructions. // @@ -195,6 +205,10 @@ public: // Print the contents of the function to PP. void print (pretty_printer *pp) const; + // Allocate an object of type T above the obstack watermark WM. + template + T *change_alloc (obstack_watermark &wm, Ts... args); + private: class bb_phi_info; class build_info; diff --git a/gcc/rtl-ssa/insns.cc b/gcc/rtl-ssa/insns.cc index 5fde3f2bb4b..2fa48e0dacd 100644 --- a/gcc/rtl-ssa/insns.cc +++ b/gcc/rtl-ssa/insns.cc @@ -192,6 +192,11 @@ insn_info::print_full (pretty_printer *pp) const pp_newline_and_indent (pp, 0); pp_string (pp, "has volatile refs"); } + if (m_is_temp) + { + pp_newline_and_indent (pp, 0); + pp_string (pp, "temporary"); + } } pp_indentation (pp) -= 2; } diff --git a/gcc/rtl-ssa/insns.h b/gcc/rtl-ssa/insns.h index a604fe295cd..6d0506706ad 100644 --- a/gcc/rtl-ssa/insns.h +++ b/gcc/rtl-ssa/insns.h @@ -306,6 +306,8 @@ public: // Print a full description of the instruction. void print_full (pretty_printer *) const; + bool is_temporary () const { return m_is_temp; } + private: // The first-order way of representing the order between instructions // is to assign "program points", with higher point numbers coming @@ -414,8 +416,11 @@ private: unsigned int m_has_pre_post_modify : 1; unsigned int m_has_volatile_refs : 1; + // Indicates the insn is a temporary / new user-allocated insn. + unsigned int m_is_temp : 1; + // For future expansion. - unsigned int m_spare : 27; + unsigned int m_spare : 26; // The program point at which the instruction occurs. // diff --git a/gcc/rtl-ssa/internals.inl b/gcc/rtl-ssa/internals.inl index e49297c12b3..907c4504352 100644 --- a/gcc/rtl-ssa/internals.inl +++ b/gcc/rtl-ssa/internals.inl @@ -415,6 +415,7 @@ inline insn_info::insn_info (bb_info *bb, rtx_insn *rtl, int cost_or_uid) m_is_asm (false), m_has_pre_post_modify (false), m_has_volatile_refs (false), + m_is_temp (false), m_spare (0), m_point (0), m_cost_or_uid (cost_or_uid), diff --git a/gcc/rtl-ssa/member-fns.inl b/gcc/rtl-ssa/member-fns.inl index ce2db045b78..b8940ca5566 100644 --- a/gcc/rtl-ssa/member-fns.inl +++ b/gcc/rtl-ssa/member-fns.inl @@ -962,4 +962,16 @@ function_info::add_regno_clobber (obstack_watermark &watermark, return true; } +template +inline T * +function_info::change_alloc (obstack_watermark &wm, Ts... args) +{ + static_assert (std::is_trivially_destructible::value, + "destructor won't be called"); + static_assert (alignof (T) <= obstack_alignment, + "too much alignment required"); + void *addr = XOBNEW (wm, T); + return new (addr) T (std::forward (args)...); +} + } diff --git a/gcc/rtl-ssa/movement.h b/gcc/rtl-ssa/movement.h index ec076db406f..41226dd3666 100644 --- a/gcc/rtl-ssa/movement.h +++ b/gcc/rtl-ssa/movement.h @@ -182,6 +182,11 @@ restrict_movement_for_defs_ignoring (insn_range_info &move_range, { for (def_info *def : defs) { + // Skip fresh defs that are being inserted, as these shouldn't + // constrain movement. + if (def->is_temporary ()) + continue; + // If the definition is a clobber, we can move it with respect // to other clobbers. // @@ -247,7 +252,8 @@ restrict_movement_for_defs_ignoring (insn_range_info &move_range, // Make sure that we don't move stores between basic blocks, since we // don't have enough information to tell whether it's safe. - if (def_info *def = memory_access (defs)) + def_info *def = memory_access (defs); + if (def && !def->is_temporary ()) { move_range = move_later_than (move_range, def->bb ()->head_insn ()); move_range = move_earlier_than (move_range, def->bb ()->end_insn ());