diff options
author | CoprDistGit <infra@openeuler.org> | 2025-02-28 10:03:49 +0000 |
---|---|---|
committer | CoprDistGit <infra@openeuler.org> | 2025-02-28 10:03:49 +0000 |
commit | 73127104a245052cd5cf29cdaaca3e5c32c70348 (patch) | |
tree | 8e28b63e478c43c252f18b49836dff7313affe54 /0142-Backport-SME-mode-switching-Add-a-target-configurabl.patch | |
parent | 49d3feaf4665cdb07576fc1a2382a4d82a612d35 (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.patch | 337 |
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 + |