From patchwork Sun Nov 5 18:50:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 161765 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:8f47:0:b0:403:3b70:6f57 with SMTP id j7csp2261443vqu; Sun, 5 Nov 2023 10:50:28 -0800 (PST) X-Google-Smtp-Source: AGHT+IHydUcnhQvR+4N79yWF1gv9iDsLbjKprQkuzKhcYjaLuqjQ0LUA3vZMqQMknYERgfEfsDLA X-Received: by 2002:ad4:5ca3:0:b0:66c:fcfc:9174 with SMTP id q3-20020ad45ca3000000b0066cfcfc9174mr39872790qvh.41.1699210228054; Sun, 05 Nov 2023 10:50:28 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1699210228; cv=pass; d=google.com; s=arc-20160816; b=HKUGByse59xc9G/5GAgideQ/DomngS8VVRdi6xxgOxyAWXZzkJmPyYPxsBP7lNEjym Cor0Lw713UvZp7SDi1G+MCHJTsKz2RbP5fvBR/6wNZddtkRjTAOgwOFKSW7JhzbNhjiF kfR2F27903bml6wv+KI6HNrICuK114B8t9R/5nnFlknXN/RkfJZtARC+tgyJxp8zQVlA eSjEjLNhJZ96q3ZELmqNlipTpKmWKZOOxH4bnemj4BIFUEw+cpCb81trLmnYyQ0qExwp MXWHsYInoMfgIDAcjTmRJRW7qHKS4Pz97z++hHacwojIl7PZcOTPSfT4d9mzPPoIM8Zf VOXQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:mime-version:user-agent :message-id:in-reply-to:date:references:subject:cc:mail-followup-to :to:from:arc-filter:dmarc-filter:delivered-to; bh=K54uoeYM+wWTkom62jNatWP3S7BI59zex2zFbITQHmc=; fh=+zKahnQ9dI9rCMQA/vTUSn1PPyLwgfSULGOjxoIZkos=; b=NBKJdHyHhJnwbImxRtIcpu6sVoS885uqeln1Ee2NpvDy4hgY34Zl2KRc09KfMk3Sdq ZIdgruGScchiQWeTkRB4PJPOSezKNxDE5WEE5uxNcBeDMPRbOrc2QEPrFpiKu3uktrGD Qnp4KtB5NELdG6hWjPhr2vnlXJKgspx3aFYMUupg+D5ouRoK8yKbGrwp9VENmHFvhih/ IX2PFFtWRiUWfmVCcGjVdWorFDdSvhqnIqffjOmcXv+83gp8WBWy8VcPX9N31Azf18RS 2ZCKxsGrHq/DXLfvDjSY22/rW+sqTTJnlyciqrCfG8Wv4/sSCWWs2nRCodn4Y6BcLY+i pWbw== ARC-Authentication-Results: i=2; mx.google.com; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id a17-20020ad441d1000000b00670bd5a370dsi4644572qvq.215.2023.11.05.10.50.27 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 05 Nov 2023 10:50:28 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A011C385735A for ; Sun, 5 Nov 2023 18:50:27 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by sourceware.org (Postfix) with ESMTP id DD1DC3856DF4 for ; Sun, 5 Nov 2023 18:50:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DD1DC3856DF4 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=arm.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org DD1DC3856DF4 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699210206; cv=none; b=tEq2qMnIQzIFcgVR+jXXS04A1i0np+4+U90sxPIDsZTaSs4bWqQkNI03hYh39TlHDbingNHRfIV3/Fh65JsLNw6m4TslT2/HeXGL7pLg3KOjir0mKqOgjMI99x9fRzjHhR559URBsLWqOyR95E50oMbiI9+Kk4OeLZW2Vs5QVm8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699210206; c=relaxed/simple; bh=C/Jk5ZnD2i/cFsvXnvmTQyWPLH7L4BsIK0nLIhD6HKY=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=Dso4NxNYnoob96LzV8TN7ZYz7mwhwsz73f+CZsEAJGkDAnmCRCxTwkmSMWVFn2ksmv1wenKGaAIWrdax6exeMQpnsARErMO4ZJXGUPFyd9QeHg9YSalh2X5yeDeG0mrdZlmf5B/YTl71/FNGshFK8MBpIbHfwXNa95lU46wJGpA= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 7EC05C15; Sun, 5 Nov 2023 10:50:47 -0800 (PST) Received: from localhost (e121540-lin.manchester.arm.com [10.32.110.72]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 3AC323F703; Sun, 5 Nov 2023 10:50:03 -0800 (PST) From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, jlaw@ventanamicro.com, richard.sandiford@arm.com Cc: jlaw@ventanamicro.com Subject: [PATCH 11/12] mode-switching: Add a target-configurable confluence operator References: Date: Sun, 05 Nov 2023 18:50:02 +0000 In-Reply-To: (Richard Sandiford's message of "Sun, 05 Nov 2023 18:45:29 +0000") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux) MIME-Version: 1.0 X-Spam-Status: No, score=-23.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1781751063816605232 X-GMAIL-MSGID: 1781751063816605232 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 b730b5bf658..cd346538fe2 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -10440,6 +10440,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 5360c1bb2d8..ae23241ea1c 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -6975,6 +6975,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 1815b397dd0..87b23d2c050 100644 --- a/gcc/mode-switching.cc +++ b/gcc/mode-switching.cc @@ -485,6 +485,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. */ @@ -568,6 +663,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]; @@ -721,6 +849,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. */ @@ -739,39 +868,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 9b14c037d3f..b08ede692f1 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -7053,6 +7053,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\