Projects
openEuler:24.03:SP1:Everything
gcc
_service:tar_scm:0142-Backport-SME-mode-switchi...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:0142-Backport-SME-mode-switching-Add-a-target-configurabl.patch of Package gcc
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
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2