137 lines
4.8 KiB
Diff
137 lines
4.8 KiB
Diff
|
|
From 194700063ed04b56d84912f7ace1b8370af6c696 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Richard Sandiford <richard.sandiford@arm.com>
|
||
|
|
Date: Sat, 11 Nov 2023 17:28:56 +0000
|
||
|
|
Subject: [PATCH 036/157] [Backport][SME] mode-switching: Fix the mode passed
|
||
|
|
to the emit hook
|
||
|
|
|
||
|
|
Reference: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=5afd208beaef50bcc43b556d4c41d41656b06436
|
||
|
|
|
||
|
|
optimize_mode_switching passes an entity's current mode (if known)
|
||
|
|
to the emit hook. However, the mode that it passed ignored the
|
||
|
|
effect of the after hook. Instead, the mode for the first emit
|
||
|
|
call in a block was taken from the incoming mode, whereas the
|
||
|
|
mode for each subsequent emit call was taken from the result
|
||
|
|
of the previous call.
|
||
|
|
|
||
|
|
The previous pass through the insns already calculated the
|
||
|
|
correct mode, so this patch records it in the seginfo structure.
|
||
|
|
(There was a 32-bit hole on 64-bit hosts, so this doesn't increase
|
||
|
|
the size of the structure for them.)
|
||
|
|
|
||
|
|
gcc/
|
||
|
|
* mode-switching.cc (seginfo): Add a prev_mode field.
|
||
|
|
(new_seginfo): Take and initialize the prev_mode.
|
||
|
|
(optimize_mode_switching): Update calls accordingly.
|
||
|
|
Use the recorded modes during the emit phase, rather than
|
||
|
|
computing one on the fly.
|
||
|
|
---
|
||
|
|
gcc/mode-switching.cc | 30 +++++++++++++++++-------------
|
||
|
|
1 file changed, 17 insertions(+), 13 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/gcc/mode-switching.cc b/gcc/mode-switching.cc
|
||
|
|
index 6a13951c9..584cd4f67 100644
|
||
|
|
--- a/gcc/mode-switching.cc
|
||
|
|
+++ b/gcc/mode-switching.cc
|
||
|
|
@@ -68,6 +68,7 @@ along with GCC; see the file COPYING3. If not see
|
||
|
|
NEXT is the next insn in the same basic block. */
|
||
|
|
struct seginfo
|
||
|
|
{
|
||
|
|
+ int prev_mode;
|
||
|
|
int mode;
|
||
|
|
rtx_insn *insn_ptr;
|
||
|
|
struct seginfo *next;
|
||
|
|
@@ -140,20 +141,22 @@ commit_mode_sets (struct edge_list *edge_list, int e, struct bb_info *info)
|
||
|
|
return need_commit;
|
||
|
|
}
|
||
|
|
|
||
|
|
-/* Allocate a new BBINFO structure, initialized with the MODE, INSN,
|
||
|
|
- and REGS_LIVE parameters.
|
||
|
|
+/* Allocate a new BBINFO structure, initialized with the PREV_MODE, MODE,
|
||
|
|
+ INSN, and REGS_LIVE parameters.
|
||
|
|
INSN may not be a NOTE_INSN_BASIC_BLOCK, unless it is an empty
|
||
|
|
basic block; that allows us later to insert instructions in a FIFO-like
|
||
|
|
manner. */
|
||
|
|
|
||
|
|
static struct seginfo *
|
||
|
|
-new_seginfo (int mode, rtx_insn *insn, const HARD_REG_SET ®s_live)
|
||
|
|
+new_seginfo (int prev_mode, int mode, rtx_insn *insn,
|
||
|
|
+ const HARD_REG_SET ®s_live)
|
||
|
|
{
|
||
|
|
struct seginfo *ptr;
|
||
|
|
|
||
|
|
gcc_assert (!NOTE_INSN_BASIC_BLOCK_P (insn)
|
||
|
|
|| insn == BB_END (NOTE_BASIC_BLOCK (insn)));
|
||
|
|
ptr = XNEW (struct seginfo);
|
||
|
|
+ ptr->prev_mode = prev_mode;
|
||
|
|
ptr->mode = mode;
|
||
|
|
ptr->insn_ptr = insn;
|
||
|
|
ptr->next = NULL;
|
||
|
|
@@ -589,7 +592,7 @@ optimize_mode_switching (void)
|
||
|
|
gcc_assert (NOTE_INSN_BASIC_BLOCK_P (ins_pos));
|
||
|
|
if (ins_pos != BB_END (bb))
|
||
|
|
ins_pos = NEXT_INSN (ins_pos);
|
||
|
|
- ptr = new_seginfo (no_mode, ins_pos, live_now);
|
||
|
|
+ ptr = new_seginfo (no_mode, no_mode, ins_pos, live_now);
|
||
|
|
add_seginfo (&tail_ptr, ptr);
|
||
|
|
for (i = 0; i < no_mode; i++)
|
||
|
|
clear_mode_bit (transp[bb->index], j, i);
|
||
|
|
@@ -605,12 +608,12 @@ optimize_mode_switching (void)
|
||
|
|
|
||
|
|
if (mode != no_mode && mode != last_mode)
|
||
|
|
{
|
||
|
|
- any_set_required = true;
|
||
|
|
- last_mode = mode;
|
||
|
|
- ptr = new_seginfo (mode, insn, live_now);
|
||
|
|
+ ptr = new_seginfo (last_mode, mode, insn, live_now);
|
||
|
|
add_seginfo (&tail_ptr, ptr);
|
||
|
|
for (i = 0; i < no_mode; i++)
|
||
|
|
clear_mode_bit (transp[bb->index], j, i);
|
||
|
|
+ any_set_required = true;
|
||
|
|
+ last_mode = mode;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (targetm.mode_switching.after)
|
||
|
|
@@ -636,7 +639,7 @@ optimize_mode_switching (void)
|
||
|
|
mark the block as nontransparent. */
|
||
|
|
if (!any_set_required)
|
||
|
|
{
|
||
|
|
- ptr = new_seginfo (no_mode, BB_END (bb), live_now);
|
||
|
|
+ ptr = new_seginfo (last_mode, no_mode, BB_END (bb), live_now);
|
||
|
|
add_seginfo (&tail_ptr, ptr);
|
||
|
|
if (last_mode != no_mode)
|
||
|
|
for (i = 0; i < no_mode; i++)
|
||
|
|
@@ -777,9 +780,9 @@ optimize_mode_switching (void)
|
||
|
|
FOR_EACH_BB_FN (bb, cfun)
|
||
|
|
{
|
||
|
|
struct seginfo *ptr, *next;
|
||
|
|
- int cur_mode = bb_info[j][bb->index].mode_in;
|
||
|
|
+ struct seginfo *first = bb_info[j][bb->index].seginfo;
|
||
|
|
|
||
|
|
- for (ptr = bb_info[j][bb->index].seginfo; ptr; ptr = next)
|
||
|
|
+ for (ptr = first; ptr; ptr = next)
|
||
|
|
{
|
||
|
|
next = ptr->next;
|
||
|
|
if (ptr->mode != no_mode)
|
||
|
|
@@ -789,14 +792,15 @@ optimize_mode_switching (void)
|
||
|
|
rtl_profile_for_bb (bb);
|
||
|
|
start_sequence ();
|
||
|
|
|
||
|
|
+ int cur_mode = (ptr == first && ptr->prev_mode == no_mode
|
||
|
|
+ ? bb_info[j][bb->index].mode_in
|
||
|
|
+ : ptr->prev_mode);
|
||
|
|
+
|
||
|
|
targetm.mode_switching.emit (entity_map[j], ptr->mode,
|
||
|
|
cur_mode, ptr->regs_live);
|
||
|
|
mode_set = get_insns ();
|
||
|
|
end_sequence ();
|
||
|
|
|
||
|
|
- /* modes kill each other inside a basic block. */
|
||
|
|
- cur_mode = ptr->mode;
|
||
|
|
-
|
||
|
|
/* Insert MODE_SET only if it is nonempty. */
|
||
|
|
if (mode_set != NULL_RTX)
|
||
|
|
{
|
||
|
|
--
|
||
|
|
2.33.0
|
||
|
|
|