summaryrefslogtreecommitdiff
path: root/0142-Backport-SME-mode-switching-Add-a-target-configurabl.patch
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2025-02-28 10:03:49 +0000
committerCoprDistGit <infra@openeuler.org>2025-02-28 10:03:49 +0000
commit73127104a245052cd5cf29cdaaca3e5c32c70348 (patch)
tree8e28b63e478c43c252f18b49836dff7313affe54 /0142-Backport-SME-mode-switching-Add-a-target-configurabl.patch
parent49d3feaf4665cdb07576fc1a2382a4d82a612d35 (diff)
automatic import of gccopeneuler24.03_LTS_SP1
Diffstat (limited to '0142-Backport-SME-mode-switching-Add-a-target-configurabl.patch')
-rw-r--r--0142-Backport-SME-mode-switching-Add-a-target-configurabl.patch337
1 files changed, 337 insertions, 0 deletions
diff --git a/0142-Backport-SME-mode-switching-Add-a-target-configurabl.patch b/0142-Backport-SME-mode-switching-Add-a-target-configurabl.patch
new file mode 100644
index 0000000..9123e40
--- /dev/null
+++ b/0142-Backport-SME-mode-switching-Add-a-target-configurabl.patch
@@ -0,0 +1,337 @@
+From 88d76baa38bb29d5cc732b3c0188b74ef9783713 Mon Sep 17 00:00:00 2001
+From: Richard Sandiford <richard.sandiford@arm.com>
+Date: Sat, 11 Nov 2023 17:28:59 +0000
+Subject: [PATCH 043/157] [Backport][SME] mode-switching: Add a
+ target-configurable confluence operator
+
+Reference: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=493b0038d7d04986c7de977074d095e4eb7d9a27
+
+The mode-switching pass assumed that all of an entity's modes
+were mutually exclusive. However, the upcoming SME changes
+have an entity with some overlapping modes, so that there is
+sometimes a "superunion" mode that contains two given modes.
+We can use this relationship to pass something more helpful than
+"don't know" to the emit hook.
+
+This patch adds a new hook that targets can use to specify
+a mode confluence operator.
+
+With mutually exclusive modes, it's possible to compute a block's
+incoming and outgoing modes by looking at its availability sets.
+With the confluence operator, we instead need to solve a full
+dataflow problem.
+
+However, when emitting a mode transition, the upcoming SME use of
+mode-switching benefits from having as much information as possible
+about the starting mode. Calculating this information is definitely
+worth the compile time.
+
+The dataflow problem is written to work before and after the LCM
+problem has been solved. A later patch makes use of this.
+
+While there (since git blame would ping me for the reindented code),
+I used a lambda to avoid the cut-&-pasted loops.
+
+gcc/
+ * target.def (mode_switching.confluence): New hook.
+ * doc/tm.texi (TARGET_MODE_CONFLUENCE): New @hook.
+ * doc/tm.texi.in: Regenerate.
+ * mode-switching.cc (confluence_info): New variable.
+ (mode_confluence, forward_confluence_n, forward_transfer): New
+ functions.
+ (optimize_mode_switching): Use them to calculate mode_in when
+ TARGET_MODE_CONFLUENCE is defined.
+---
+ gcc/doc/tm.texi | 16 ++++
+ gcc/doc/tm.texi.in | 2 +
+ gcc/mode-switching.cc | 179 +++++++++++++++++++++++++++++++++++-------
+ gcc/target.def | 17 ++++
+ 4 files changed, 186 insertions(+), 28 deletions(-)
+
+diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
+index 7fce485b2..d7053ec9e 100644
+--- a/gcc/doc/tm.texi
++++ b/gcc/doc/tm.texi
+@@ -10306,6 +10306,22 @@ the number of modes if it does not know what mode @var{entity} has after
+ Not defining the hook is equivalent to returning @var{mode}.
+ @end deftypefn
+
++@deftypefn {Target Hook} int TARGET_MODE_CONFLUENCE (int @var{entity}, int @var{mode1}, int @var{mode2})
++By default, the mode-switching pass assumes that a given entity's modes
++are mutually exclusive. This means that the pass can only tell
++@code{TARGET_MODE_EMIT} about an entity's previous mode if all
++incoming paths of execution leave the entity in the same state.
++
++However, some entities might have overlapping, non-exclusive modes,
++so that it is sometimes possible to represent ``mode @var{mode1} or mode
++@var{mode2}'' with something more specific than ``mode not known''.
++If this is true for at least one entity, you should define this hook
++and make it return a mode that includes @var{mode1} and @var{mode2}
++as possibilities. (The mode can include other possibilities too.)
++The hook should return the number of modes if no suitable mode exists
++for the given arguments.
++@end deftypefn
++
+ @deftypefn {Target Hook} int TARGET_MODE_ENTRY (int @var{entity})
+ If this hook is defined, it is evaluated for every @var{entity} that
+ needs mode switching. It should return the mode that @var{entity} is
+diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
+index ad343504f..d420e62fd 100644
+--- a/gcc/doc/tm.texi.in
++++ b/gcc/doc/tm.texi.in
+@@ -6922,6 +6922,8 @@ mode or ``no mode'', depending on context.
+
+ @hook TARGET_MODE_AFTER
+
++@hook TARGET_MODE_CONFLUENCE
++
+ @hook TARGET_MODE_ENTRY
+
+ @hook TARGET_MODE_EXIT
+diff --git a/gcc/mode-switching.cc b/gcc/mode-switching.cc
+index 89a8494c6..065767902 100644
+--- a/gcc/mode-switching.cc
++++ b/gcc/mode-switching.cc
+@@ -484,6 +484,101 @@ create_pre_exit (int n_entities, int *entity_map, const int *num_modes)
+ return pre_exit;
+ }
+
++/* Return the confluence of modes MODE1 and MODE2 for entity ENTITY,
++ using NO_MODE to represent an unknown mode if nothing more precise
++ is available. */
++
++int
++mode_confluence (int entity, int mode1, int mode2, int no_mode)
++{
++ if (mode1 == mode2)
++ return mode1;
++
++ if (mode1 != no_mode
++ && mode2 != no_mode
++ && targetm.mode_switching.confluence)
++ return targetm.mode_switching.confluence (entity, mode1, mode2);
++
++ return no_mode;
++}
++
++/* Information for the dataflow problems below. */
++struct
++{
++ /* Information about each basic block, indexed by block id. */
++ struct bb_info *bb_info;
++
++ /* The entity that we're processing. */
++ int entity;
++
++ /* The number of modes defined for the entity, and thus the identifier
++ of the "don't know" mode. */
++ int no_mode;
++} confluence_info;
++
++/* Propagate information about any mode change on edge E to the
++ destination block's mode_in. Return true if something changed.
++
++ The mode_in and mode_out fields use no_mode + 1 to mean "not yet set". */
++
++static bool
++forward_confluence_n (edge e)
++{
++ /* The entry and exit blocks have no useful mode information. */
++ if (e->src->index == ENTRY_BLOCK || e->dest->index == EXIT_BLOCK)
++ return false;
++
++ /* We don't control mode changes across abnormal edges. */
++ if (e->flags & EDGE_ABNORMAL)
++ return false;
++
++ /* E->aux is nonzero if we have computed the LCM problem and scheduled
++ E to change the mode to E->aux - 1. Otherwise model the change
++ from the source to the destination. */
++ struct bb_info *bb_info = confluence_info.bb_info;
++ int no_mode = confluence_info.no_mode;
++ int src_mode = bb_info[e->src->index].mode_out;
++ if (e->aux)
++ src_mode = (int) (intptr_t) e->aux - 1;
++ if (src_mode == no_mode + 1)
++ return false;
++
++ int dest_mode = bb_info[e->dest->index].mode_in;
++ if (dest_mode == no_mode + 1)
++ {
++ bb_info[e->dest->index].mode_in = src_mode;
++ return true;
++ }
++
++ int entity = confluence_info.entity;
++ int new_mode = mode_confluence (entity, src_mode, dest_mode, no_mode);
++ if (dest_mode == new_mode)
++ return false;
++
++ bb_info[e->dest->index].mode_in = new_mode;
++ return true;
++}
++
++/* Update block BB_INDEX's mode_out based on its mode_in. Return true if
++ something changed. */
++
++static bool
++forward_transfer (int bb_index)
++{
++ /* The entry and exit blocks have no useful mode information. */
++ if (bb_index == ENTRY_BLOCK || bb_index == EXIT_BLOCK)
++ return false;
++
++ /* Only propagate through a block if the entity is transparent. */
++ struct bb_info *bb_info = confluence_info.bb_info;
++ if (bb_info[bb_index].computing != confluence_info.no_mode
++ || bb_info[bb_index].mode_out == bb_info[bb_index].mode_in)
++ return false;
++
++ bb_info[bb_index].mode_out = bb_info[bb_index].mode_in;
++ return true;
++}
++
+ /* Find all insns that need a particular mode setting, and insert the
+ necessary mode switches. Return true if we did work. */
+
+@@ -567,6 +662,39 @@ optimize_mode_switching (void)
+
+ auto_sbitmap transp_all (last_basic_block_for_fn (cfun));
+
++ auto_bitmap blocks;
++
++ /* Forward-propagate mode information through blocks where the entity
++ is transparent, so that mode_in describes the mode on entry to each
++ block and mode_out describes the mode on exit from each block. */
++ auto forwprop_mode_info = [&](struct bb_info *info,
++ int entity, int no_mode)
++ {
++ /* Use no_mode + 1 to mean "not yet set". */
++ FOR_EACH_BB_FN (bb, cfun)
++ {
++ if (bb_has_abnormal_pred (bb))
++ info[bb->index].mode_in = info[bb->index].seginfo->mode;
++ else
++ info[bb->index].mode_in = no_mode + 1;
++ if (info[bb->index].computing != no_mode)
++ info[bb->index].mode_out = info[bb->index].computing;
++ else
++ info[bb->index].mode_out = no_mode + 1;
++ }
++
++ confluence_info.bb_info = info;
++ confluence_info.entity = entity;
++ confluence_info.no_mode = no_mode;
++
++ bitmap_set_range (blocks, 0, last_basic_block_for_fn (cfun));
++ df_simple_dataflow (DF_FORWARD, NULL, NULL, forward_confluence_n,
++ forward_transfer, blocks,
++ df_get_postorder (DF_FORWARD),
++ df_get_n_blocks (DF_FORWARD));
++
++ };
++
+ for (j = n_entities - 1; j >= 0; j--)
+ {
+ int e = entity_map[j];
+@@ -720,6 +848,7 @@ optimize_mode_switching (void)
+ for (j = n_entities - 1; j >= 0; j--)
+ {
+ int no_mode = num_modes[entity_map[j]];
++ struct bb_info *info = bb_info[j];
+
+ /* Insert all mode sets that have been inserted by lcm. */
+
+@@ -740,39 +869,33 @@ optimize_mode_switching (void)
+ }
+ }
+
++ /* mode_in and mode_out can be calculated directly from avin and
++ avout if all the modes are mutually exclusive. Use the target-
++ provided confluence function otherwise. */
++ if (targetm.mode_switching.confluence)
++ forwprop_mode_info (info, entity_map[j], no_mode);
++
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+- struct bb_info *info = bb_info[j];
+- int last_mode = no_mode;
+-
+- /* intialize mode in availability for bb. */
+- for (i = 0; i < no_mode; i++)
+- if (mode_bit_p (avout[bb->index], j, i))
+- {
+- if (last_mode == no_mode)
+- last_mode = i;
+- if (last_mode != i)
++ auto modes_confluence = [&](sbitmap *av)
++ {
++ for (int i = 0; i < no_mode; ++i)
++ if (mode_bit_p (av[bb->index], j, i))
+ {
+- last_mode = no_mode;
+- break;
++ for (int i2 = i + 1; i2 < no_mode; ++i2)
++ if (mode_bit_p (av[bb->index], j, i2))
++ return no_mode;
++ return i;
+ }
+- }
+- info[bb->index].mode_out = last_mode;
++ return no_mode;
++ };
+
+- /* intialize mode out availability for bb. */
+- last_mode = no_mode;
+- for (i = 0; i < no_mode; i++)
+- if (mode_bit_p (avin[bb->index], j, i))
+- {
+- if (last_mode == no_mode)
+- last_mode = i;
+- if (last_mode != i)
+- {
+- last_mode = no_mode;
+- break;
+- }
+- }
+- info[bb->index].mode_in = last_mode;
++ /* intialize mode in/out availability for bb. */
++ if (!targetm.mode_switching.confluence)
++ {
++ info[bb->index].mode_out = modes_confluence (avout);
++ info[bb->index].mode_in = modes_confluence (avin);
++ }
+
+ for (i = 0; i < no_mode; i++)
+ if (mode_bit_p (del[bb->index], j, i))
+diff --git a/gcc/target.def b/gcc/target.def
+index 67c20bbb0..1e2091ed3 100644
+--- a/gcc/target.def
++++ b/gcc/target.def
+@@ -7025,6 +7025,23 @@ the number of modes if it does not know what mode @var{entity} has after\n\
+ Not defining the hook is equivalent to returning @var{mode}.",
+ int, (int entity, int mode, rtx_insn *insn, HARD_REG_SET regs_live), NULL)
+
++DEFHOOK
++(confluence,
++ "By default, the mode-switching pass assumes that a given entity's modes\n\
++are mutually exclusive. This means that the pass can only tell\n\
++@code{TARGET_MODE_EMIT} about an entity's previous mode if all\n\
++incoming paths of execution leave the entity in the same state.\n\
++\n\
++However, some entities might have overlapping, non-exclusive modes,\n\
++so that it is sometimes possible to represent ``mode @var{mode1} or mode\n\
++@var{mode2}'' with something more specific than ``mode not known''.\n\
++If this is true for at least one entity, you should define this hook\n\
++and make it return a mode that includes @var{mode1} and @var{mode2}\n\
++as possibilities. (The mode can include other possibilities too.)\n\
++The hook should return the number of modes if no suitable mode exists\n\
++for the given arguments.",
++ int, (int entity, int mode1, int mode2), NULL)
++
+ DEFHOOK
+ (entry,
+ "If this hook is defined, it is evaluated for every @var{entity} that\n\
+--
+2.33.0
+