From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ej1-x62d.google.com (mail-ej1-x62d.google.com [IPv6:2a00:1450:4864:20::62d]) by sourceware.org (Postfix) with ESMTPS id 61B713858D1E for ; Thu, 7 Sep 2023 07:56:32 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 61B713858D1E Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ej1-x62d.google.com with SMTP id a640c23a62f3a-99c4923195dso71585866b.2 for ; Thu, 07 Sep 2023 00:56:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1694073391; x=1694678191; darn=gcc.gnu.org; h=content-transfer-encoding:in-reply-to:from:references:to :content-language:subject:cc:user-agent:mime-version:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=g7hRd0tPeYnIMNIyscFL5UaxSgImNhfLwiDUG23Cvmw=; b=nOd8sHHTt2BAOiTkXZ+iUVVNyp/CmCtAY1pan7q7bZFPaOjBXHBOWiaTt+Tz4VluYf KRRBZPb1tavA6d7Dezgw1F1YLghcpj9sp65oDH5Nx4Bhy/vDE5LhVl1Da/ta+Fc+IHT5 +KQ7rVKX+qEG0u/IvM6Sw0A0OneGoScOIDU1fxOLJFwtA4NHJ2C8rHU/sYpsi+sCuozH 79oDD5tlP0oYsA3oKUa+U/N9qnHchJqglJBqfQU/rgUhqwA15ikafjqSOA9M3+aKj4Dr wInMSC/HU3M+v/Oy/IW22ontvVpx6XZ292fUnjQpkXGrio1gg+mxCtoxXPYaPsbQYEE5 DhlQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1694073391; x=1694678191; h=content-transfer-encoding:in-reply-to:from:references:to :content-language:subject:cc:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=g7hRd0tPeYnIMNIyscFL5UaxSgImNhfLwiDUG23Cvmw=; b=gyLrqZ2m0OmFhHxIdOpnI6eRUzAy7upeqqlVmNQXQPy1eDJ4Dt/Va+nuzeGYU4Y+f5 cHNwOUWPaAcy6lF26BzMJft7eJY7+5JGq3YKq70K7zlKJUBdDASBGSnhCDwqFsJP8dxG davGBu+abrmddkf8dj5XFyX0+hbvjwypA4oqie77P4+nfrMkLcQJ+WnH3sINIaVXcFDK V7lDZlR3RUnB2mbssYn6rTc/oU+I4toDc1enfkieet5BuAu1gI3gI3ynRubVI4mNEmW1 c0TBHjEVgAvF/SMX+SEPqRFvL9jqToyOhePC08vE1Oc2Gjf7GtzH2yXwJBrmiAwY68fP 2zgA== X-Gm-Message-State: AOJu0Yw2sqZYwgQhgPGXUogtvFlE41ARYSycy0kC/2bvCqT4EmHD7Cfj b+Yio2eGSJu7snwrpy0V9Pc= X-Google-Smtp-Source: AGHT+IElpIy7LVYMJ+0CPba4dY+WIHIWDJ/x+IUS1eeqFQJJ+n30DBCeO5QqxXP2Loc5DPWKCq2C8g== X-Received: by 2002:a17:906:3044:b0:9a4:88af:b7b with SMTP id d4-20020a170906304400b009a488af0b7bmr4055668ejd.62.1694073390708; Thu, 07 Sep 2023 00:56:30 -0700 (PDT) Received: from [192.168.1.23] (ip-046-005-130-086.um12.pools.vodafone-ip.de. [46.5.130.86]) by smtp.gmail.com with ESMTPSA id q8-20020a170906940800b00988c0c175c6sm10106201ejx.189.2023.09.07.00.56.30 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 07 Sep 2023 00:56:30 -0700 (PDT) Message-ID: <3e0c212c-ef1b-26a6-3515-724cd2bc870f@gmail.com> Date: Thu, 7 Sep 2023 09:56:29 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.13.0 Cc: rdapp.gcc@gmail.com Subject: Re: [PATCH] fwprop: Allow UNARY_P and check register pressure. Content-Language: en-US To: Jeff Law , gcc-patches , richard.sandiford@arm.com References: <5a90c8a9-1570-5af4-bfdc-19d097bfee6e@gmail.com> <9acc1a24-5d01-40ad-b4b2-5948585d3e8c@gmail.com> <48bed106-190e-ab5f-4099-fdfd4f5a193f@gmail.com> <77daf152-e1fe-4980-8297-d37901d925e8@gmail.com> From: Robin Dapp In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-10.0 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,GIT_PATCH_0,KAM_SHORT,NICE_REPLY_A,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: > Thanks for giving it a go. Can you post the latest version of the > regpressure patch too? The previous on-list version I could find > seems to be too old. Oh, sure, attached. Apologies, I added the regpressure_same_class convenience helper but forgot to re-send it. Regards Robin >From d3f87e4de7d7d05a2fcf8c948097b14eadf08c90 Mon Sep 17 00:00:00 2001 From: Robin Dapp Date: Mon, 24 Jul 2023 16:25:38 +0200 Subject: [PATCH] gcse: Extract reg pressure handling into separate file. This patch extracts the hoist-pressure handling from gcse and puts it into a separate file so it can be used by other passes in the future. No functional change. gcc/ChangeLog: * Makefile.in: Add regpressure.o. * gcse.cc (struct bb_data): Move to regpressure.cc. (BB_DATA): Ditto. (get_regno_pressure_class): Ditto. (get_pressure_class_and_nregs): Ditto. (record_set_data): Ditto. (update_bb_reg_pressure): Ditto. (should_hoist_expr_to_dom): Ditto. (hoist_code): Ditto. (change_pressure): Ditto. (calculate_bb_reg_pressure): Ditto. (one_code_hoisting_pass): Ditto. * gcse.h (single_set_gcse): Export single_set_gcse. * regpressure.cc: New file. * regpressure.h: New file. --- gcc/Makefile.in | 1 + gcc/gcse.cc | 304 ++--------------------------------- gcc/gcse.h | 2 + gcc/regpressure.cc | 391 +++++++++++++++++++++++++++++++++++++++++++++ gcc/regpressure.h | 48 ++++++ 5 files changed, 459 insertions(+), 287 deletions(-) create mode 100644 gcc/regpressure.cc create mode 100644 gcc/regpressure.h diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 5930b52462a..62768a84f81 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1610,6 +1610,7 @@ OBJS = \ reg-stack.o \ regcprop.o \ reginfo.o \ + regpressure.o \ regrename.o \ regstat.o \ reload.o \ diff --git a/gcc/gcse.cc b/gcc/gcse.cc index f689c0c2687..5bafef7970f 100644 --- a/gcc/gcse.cc +++ b/gcc/gcse.cc @@ -160,6 +160,7 @@ along with GCC; see the file COPYING3. If not see #include "gcse.h" #include "gcse-common.h" #include "function-abi.h" +#include "regpressure.h" /* We support GCSE via Partial Redundancy Elimination. PRE optimizations are a superset of those done by classic GCSE. @@ -419,30 +420,6 @@ static bool doing_code_hoisting_p = false; /* For available exprs */ static sbitmap *ae_kill; -/* Data stored for each basic block. */ -struct bb_data -{ - /* Maximal register pressure inside basic block for given register class - (defined only for the pressure classes). */ - int max_reg_pressure[N_REG_CLASSES]; - /* Recorded register pressure of basic block before trying to hoist - an expression. Will be used to restore the register pressure - if the expression should not be hoisted. */ - int old_pressure; - /* Recorded register live_in info of basic block during code hoisting - process. BACKUP is used to record live_in info before trying to - hoist an expression, and will be used to restore LIVE_IN if the - expression should not be hoisted. */ - bitmap live_in, backup; -}; - -#define BB_DATA(bb) ((struct bb_data *) (bb)->aux) - -static basic_block curr_bb; - -/* Current register pressure for each pressure class. */ -static int curr_reg_pressure[N_REG_CLASSES]; - static void compute_can_copy (void); static void *gmalloc (size_t) ATTRIBUTE_MALLOC; @@ -494,8 +471,6 @@ static bool should_hoist_expr_to_dom (basic_block, struct gcse_expr *, enum reg_class, int *, bitmap, rtx_insn *); static bool hoist_code (void); -static enum reg_class get_regno_pressure_class (int regno, int *nregs); -static enum reg_class get_pressure_class_and_nregs (rtx_insn *insn, int *nregs); static bool one_code_hoisting_pass (void); static rtx_insn *process_insert_insn (struct gcse_expr *); static bool pre_edge_insert (struct edge_list *, struct gcse_expr **); @@ -2402,7 +2377,7 @@ record_set_data (rtx dest, const_rtx set, void *data) } } -static const_rtx +const_rtx single_set_gcse (rtx_insn *insn) { struct set_data s; @@ -2804,72 +2779,6 @@ compute_code_hoist_data (void) fprintf (dump_file, "\n"); } -/* Update register pressure for BB when hoisting an expression from - instruction FROM, if live ranges of inputs are shrunk. Also - maintain live_in information if live range of register referred - in FROM is shrunk. - - Return 0 if register pressure doesn't change, otherwise return - the number by which register pressure is decreased. - - NOTE: Register pressure won't be increased in this function. */ - -static int -update_bb_reg_pressure (basic_block bb, rtx_insn *from) -{ - rtx dreg; - rtx_insn *insn; - basic_block succ_bb; - df_ref use, op_ref; - edge succ; - edge_iterator ei; - int decreased_pressure = 0; - int nregs; - enum reg_class pressure_class; - - FOR_EACH_INSN_USE (use, from) - { - dreg = DF_REF_REAL_REG (use); - /* The live range of register is shrunk only if it isn't: - 1. referred on any path from the end of this block to EXIT, or - 2. referred by insns other than FROM in this block. */ - FOR_EACH_EDGE (succ, ei, bb->succs) - { - succ_bb = succ->dest; - if (succ_bb == EXIT_BLOCK_PTR_FOR_FN (cfun)) - continue; - - if (bitmap_bit_p (BB_DATA (succ_bb)->live_in, REGNO (dreg))) - break; - } - if (succ != NULL) - continue; - - op_ref = DF_REG_USE_CHAIN (REGNO (dreg)); - for (; op_ref; op_ref = DF_REF_NEXT_REG (op_ref)) - { - if (!DF_REF_INSN_INFO (op_ref)) - continue; - - insn = DF_REF_INSN (op_ref); - if (BLOCK_FOR_INSN (insn) == bb - && NONDEBUG_INSN_P (insn) && insn != from) - break; - } - - pressure_class = get_regno_pressure_class (REGNO (dreg), &nregs); - /* Decrease register pressure and update live_in information for - this block. */ - if (!op_ref && pressure_class != NO_REGS) - { - decreased_pressure += nregs; - BB_DATA (bb)->max_reg_pressure[pressure_class] -= nregs; - bitmap_clear_bit (BB_DATA (bb)->live_in, REGNO (dreg)); - } - } - return decreased_pressure; -} - /* Determine if the expression EXPR should be hoisted to EXPR_BB up in flow graph, if it can reach BB unimpared. Stop the search if the expression would need to be moved more than DISTANCE instructions. @@ -2917,12 +2826,9 @@ should_hoist_expr_to_dom (basic_block expr_bb, struct gcse_expr *expr, /* Record old information of basic block BB when it is visited at the first time. */ if (!bitmap_bit_p (hoisted_bbs, bb->index)) - { - struct bb_data *data = BB_DATA (bb); - bitmap_copy (data->backup, data->live_in); - data->old_pressure = data->max_reg_pressure[pressure_class]; - } - decreased_pressure = update_bb_reg_pressure (bb, from); + regpressure_init_bb_info (bb, pressure_class); + + decreased_pressure = regpressure_update_bb_reg_pressure (bb, from); } /* Terminate the search if distance, for which EXPR is allowed to move, is exhausted. */ @@ -2945,8 +2851,7 @@ should_hoist_expr_to_dom (basic_block expr_bb, struct gcse_expr *expr, on ARM target, while it has no obvious effect on other targets like x86, x86_64, mips and powerpc. */ else if (CONST_INT_P (expr->expr) - || (BB_DATA (bb)->max_reg_pressure[pressure_class] - >= ira_class_hard_regs_num[pressure_class] + || (!regpressure_viable (bb, pressure_class) && decreased_pressure < *nregs)) distance -= bb_size[bb->index]; } @@ -3073,7 +2978,6 @@ hoist_code (void) int *to_bb_head; int *bb_size; bool changed = false; - struct bb_data *data; /* Basic blocks that have occurrences reachable from BB. */ bitmap from_bbs; /* Basic blocks through which expr is hoisted. */ @@ -3206,8 +3110,9 @@ hoist_code (void) max_distance += (bb_size[dominated->index] - to_bb_head[INSN_UID (occr->insn)]); - pressure_class = get_pressure_class_and_nregs (occr->insn, - &nregs); + pressure_class = + regpressure_get_pressure_class_and_nregs (occr->insn, + &nregs); /* Note if the expression should be hoisted from the dominated block to BB if it can reach DOMINATED unimpared. @@ -3262,13 +3167,11 @@ hoist_code (void) /* Increase register pressure of basic blocks to which expr is hoisted because of extended live range of output. */ - data = BB_DATA (bb); - data->max_reg_pressure[pressure_class] += nregs; + regpressure_increase (bb, pressure_class, nregs); + EXECUTE_IF_SET_IN_BITMAP (hoisted_bbs, 0, k, bi) - { - data = BB_DATA (BASIC_BLOCK_FOR_FN (cfun, k)); - data->max_reg_pressure[pressure_class] += nregs; - } + regpressure_increase (BASIC_BLOCK_FOR_FN (cfun, k), + pressure_class, nregs); } else if (flag_ira_hoist_pressure) { @@ -3276,12 +3179,8 @@ hoist_code (void) blocks recorded in hoisted_bbs when expr will not be hoisted. */ EXECUTE_IF_SET_IN_BITMAP (hoisted_bbs, 0, k, bi) - { - data = BB_DATA (BASIC_BLOCK_FOR_FN (cfun, k)); - bitmap_copy (data->live_in, data->backup); - data->max_reg_pressure[pressure_class] - = data->old_pressure; - } + regpressure_reset (BASIC_BLOCK_FOR_FN (cfun, k), + pressure_class); } if (flag_ira_hoist_pressure) @@ -3343,166 +3242,6 @@ hoist_code (void) return changed; } -/* Return pressure class and number of needed hard registers (through - *NREGS) of register REGNO. */ -static enum reg_class -get_regno_pressure_class (int regno, int *nregs) -{ - if (regno >= FIRST_PSEUDO_REGISTER) - { - enum reg_class pressure_class; - - pressure_class = reg_allocno_class (regno); - pressure_class = ira_pressure_class_translate[pressure_class]; - *nregs - = ira_reg_class_max_nregs[pressure_class][PSEUDO_REGNO_MODE (regno)]; - return pressure_class; - } - else if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno) - && ! TEST_HARD_REG_BIT (eliminable_regset, regno)) - { - *nregs = 1; - return ira_pressure_class_translate[REGNO_REG_CLASS (regno)]; - } - else - { - *nregs = 0; - return NO_REGS; - } -} - -/* Return pressure class and number of hard registers (through *NREGS) - for destination of INSN. */ -static enum reg_class -get_pressure_class_and_nregs (rtx_insn *insn, int *nregs) -{ - rtx reg; - enum reg_class pressure_class; - const_rtx set = single_set_gcse (insn); - - reg = SET_DEST (set); - if (GET_CODE (reg) == SUBREG) - reg = SUBREG_REG (reg); - if (MEM_P (reg)) - { - *nregs = 0; - pressure_class = NO_REGS; - } - else - { - gcc_assert (REG_P (reg)); - pressure_class = reg_allocno_class (REGNO (reg)); - pressure_class = ira_pressure_class_translate[pressure_class]; - *nregs - = ira_reg_class_max_nregs[pressure_class][GET_MODE (SET_SRC (set))]; - } - return pressure_class; -} - -/* Increase (if INCR_P) or decrease current register pressure for - register REGNO. */ -static void -change_pressure (int regno, bool incr_p) -{ - int nregs; - enum reg_class pressure_class; - - pressure_class = get_regno_pressure_class (regno, &nregs); - if (! incr_p) - curr_reg_pressure[pressure_class] -= nregs; - else - { - curr_reg_pressure[pressure_class] += nregs; - if (BB_DATA (curr_bb)->max_reg_pressure[pressure_class] - < curr_reg_pressure[pressure_class]) - BB_DATA (curr_bb)->max_reg_pressure[pressure_class] - = curr_reg_pressure[pressure_class]; - } -} - -/* Calculate register pressure for each basic block by walking insns - from last to first. */ -static void -calculate_bb_reg_pressure (void) -{ - int i; - unsigned int j; - rtx_insn *insn; - basic_block bb; - bitmap curr_regs_live; - bitmap_iterator bi; - - - ira_setup_eliminable_regset (); - curr_regs_live = BITMAP_ALLOC (®_obstack); - FOR_EACH_BB_FN (bb, cfun) - { - curr_bb = bb; - BB_DATA (bb)->live_in = BITMAP_ALLOC (NULL); - BB_DATA (bb)->backup = BITMAP_ALLOC (NULL); - bitmap_copy (BB_DATA (bb)->live_in, df_get_live_in (bb)); - bitmap_copy (curr_regs_live, df_get_live_out (bb)); - for (i = 0; i < ira_pressure_classes_num; i++) - curr_reg_pressure[ira_pressure_classes[i]] = 0; - EXECUTE_IF_SET_IN_BITMAP (curr_regs_live, 0, j, bi) - change_pressure (j, true); - - FOR_BB_INSNS_REVERSE (bb, insn) - { - rtx dreg; - int regno; - df_ref def, use; - - if (! NONDEBUG_INSN_P (insn)) - continue; - - FOR_EACH_INSN_DEF (def, insn) - { - dreg = DF_REF_REAL_REG (def); - gcc_assert (REG_P (dreg)); - regno = REGNO (dreg); - if (!(DF_REF_FLAGS (def) - & (DF_REF_PARTIAL | DF_REF_CONDITIONAL))) - { - if (bitmap_clear_bit (curr_regs_live, regno)) - change_pressure (regno, false); - } - } - - FOR_EACH_INSN_USE (use, insn) - { - dreg = DF_REF_REAL_REG (use); - gcc_assert (REG_P (dreg)); - regno = REGNO (dreg); - if (bitmap_set_bit (curr_regs_live, regno)) - change_pressure (regno, true); - } - } - } - BITMAP_FREE (curr_regs_live); - - if (dump_file == NULL) - return; - - fprintf (dump_file, "\nRegister Pressure: \n"); - FOR_EACH_BB_FN (bb, cfun) - { - fprintf (dump_file, " Basic block %d: \n", bb->index); - for (i = 0; (int) i < ira_pressure_classes_num; i++) - { - enum reg_class pressure_class; - - pressure_class = ira_pressure_classes[i]; - if (BB_DATA (bb)->max_reg_pressure[pressure_class] == 0) - continue; - - fprintf (dump_file, " %s=%d\n", reg_class_names[pressure_class], - BB_DATA (bb)->max_reg_pressure[pressure_class]); - } - } - fprintf (dump_file, "\n"); -} - /* Top level routine to perform one code hoisting (aka unification) pass Return true if a change was made. */ @@ -3524,13 +3263,7 @@ one_code_hoisting_pass (void) /* Calculate register pressure for each basic block. */ if (flag_ira_hoist_pressure) - { - regstat_init_n_sets_and_refs (); - ira_set_pseudo_classes (false, dump_file); - alloc_aux_for_blocks (sizeof (struct bb_data)); - calculate_bb_reg_pressure (); - regstat_free_n_sets_and_refs (); - } + regpressure_init (); /* We need alias. */ init_alias_analysis (); @@ -3554,10 +3287,7 @@ one_code_hoisting_pass (void) } if (flag_ira_hoist_pressure) - { - free_aux_for_blocks (); - free_reg_info (); - } + regpressure_cleanup (); free_hash_table (&expr_hash_table); free_gcse_mem (); obstack_free (&gcse_obstack, NULL); diff --git a/gcc/gcse.h b/gcc/gcse.h index e68afdcea21..1162086570d 100644 --- a/gcc/gcse.h +++ b/gcc/gcse.h @@ -43,4 +43,6 @@ void gcse_cc_finalize (void); extern bool gcse_or_cprop_is_too_expensive (const char *); extern rtx_insn *insert_insn_end_basic_block (rtx_insn *, basic_block); +const_rtx single_set_gcse (rtx_insn *insn); + #endif diff --git a/gcc/regpressure.cc b/gcc/regpressure.cc new file mode 100644 index 00000000000..7846d320a66 --- /dev/null +++ b/gcc/regpressure.cc @@ -0,0 +1,391 @@ +/* Register pressure helper functions. + Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "target.h" +#include "rtl.h" +#include "df.h" +#include "memmodel.h" +#include "tm_p.h" +#include "regs.h" +#include "ira.h" +#include "gcse.h" +#include "gcse-common.h" +#include "regpressure.h" + +struct bb_data +{ + /* Maximal register pressure inside basic block for given register class + (defined only for the pressure classes). */ + int max_reg_pressure[N_REG_CLASSES]; + /* Recorded register pressure of basic block before trying to hoist + an expression. Will be used to restore the register pressure + if the expression should not be hoisted. */ + int old_pressure; + /* Recorded register live_in info of basic block during code hoisting + process. BACKUP is used to record live_in info before trying to + hoist an expression, and will be used to restore LIVE_IN if the + expression should not be hoisted. */ + bitmap live_in, backup; +}; + +#define BB_DATA(bb) ((struct bb_data *) (bb)->aux) + +static basic_block curr_bb; + +/* Current register pressure for each pressure class. */ +static int curr_reg_pressure[N_REG_CLASSES]; + +/* Update register pressure for BB when hoisting an expression from + instruction FROM, if live ranges of inputs are shrunk. Also + maintain live_in information if live range of register referred + in FROM is shrunk. + + Return 0 if register pressure doesn't change, otherwise return + the number by which register pressure is decreased. + + NOTE: Register pressure won't be increased in this function. */ + +int +regpressure_update_bb_reg_pressure (basic_block bb, rtx_insn *from) +{ + rtx dreg; + rtx_insn *insn; + basic_block succ_bb; + df_ref use, op_ref; + edge succ; + edge_iterator ei; + int decreased_pressure = 0; + int nregs; + enum reg_class pressure_class; + + FOR_EACH_INSN_USE (use, from) + { + dreg = DF_REF_REAL_REG (use); + /* The live range of register is shrunk only if it isn't: + 1. referred on any path from the end of this block to EXIT, or + 2. referred by insns other than FROM in this block. */ + FOR_EACH_EDGE (succ, ei, bb->succs) + { + succ_bb = succ->dest; + if (succ_bb == EXIT_BLOCK_PTR_FOR_FN (cfun)) + continue; + + if (regpressure_is_live_in (succ_bb, REGNO (dreg))) + break; + } + if (succ != NULL) + continue; + + op_ref = DF_REG_USE_CHAIN (REGNO (dreg)); + for (; op_ref; op_ref = DF_REF_NEXT_REG (op_ref)) + { + if (!DF_REF_INSN_INFO (op_ref)) + continue; + + insn = DF_REF_INSN (op_ref); + if (BLOCK_FOR_INSN (insn) == bb && NONDEBUG_INSN_P (insn) + && insn != from) + break; + } + + pressure_class + = regpressure_get_regno_pressure_class (REGNO (dreg), &nregs); + /* Decrease register pressure and update live_in information for + this block. */ + if (!op_ref && pressure_class != NO_REGS) + { + decreased_pressure += nregs; + regpressure_decrease (bb, pressure_class, nregs); + regpressure_clear_live_in (bb, REGNO (dreg)); + } + } + return decreased_pressure; +} + +/* Increase (if INCR_P) or decrease current register pressure for + register REGNO. */ +static void +change_pressure (int regno, bool incr_p) +{ + int nregs; + enum reg_class pressure_class; + + pressure_class = regpressure_get_regno_pressure_class (regno, &nregs); + if (!incr_p) + curr_reg_pressure[pressure_class] -= nregs; + else + { + curr_reg_pressure[pressure_class] += nregs; + if (regpressure_get (curr_bb, pressure_class) + < curr_reg_pressure[pressure_class]) + BB_DATA (curr_bb)->max_reg_pressure[pressure_class] + = curr_reg_pressure[pressure_class]; + } +} + +/* Calculate register pressure for each basic block by walking insns + from last to first. */ +static void +calculate_bb_reg_pressure (void) +{ + int i; + unsigned int j; + rtx_insn *insn; + basic_block bb; + bitmap curr_regs_live; + bitmap_iterator bi; + + ira_setup_eliminable_regset (); + curr_regs_live = BITMAP_ALLOC (®_obstack); + FOR_EACH_BB_FN (bb, cfun) + { + curr_bb = bb; + BB_DATA (bb)->live_in = BITMAP_ALLOC (NULL); + BB_DATA (bb)->backup = BITMAP_ALLOC (NULL); + bitmap_copy (BB_DATA (bb)->live_in, df_get_live_in (bb)); + bitmap_copy (curr_regs_live, df_get_live_out (bb)); + for (i = 0; i < ira_pressure_classes_num; i++) + curr_reg_pressure[ira_pressure_classes[i]] = 0; + EXECUTE_IF_SET_IN_BITMAP (curr_regs_live, 0, j, bi) + change_pressure (j, true); + + FOR_BB_INSNS_REVERSE (bb, insn) + { + rtx dreg; + int regno; + df_ref def, use; + + if (!NONDEBUG_INSN_P (insn)) + continue; + + FOR_EACH_INSN_DEF (def, insn) + { + dreg = DF_REF_REAL_REG (def); + gcc_assert (REG_P (dreg)); + regno = REGNO (dreg); + if (!(DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL))) + { + if (bitmap_clear_bit (curr_regs_live, regno)) + change_pressure (regno, false); + } + } + + FOR_EACH_INSN_USE (use, insn) + { + dreg = DF_REF_REAL_REG (use); + gcc_assert (REG_P (dreg)); + regno = REGNO (dreg); + if (bitmap_set_bit (curr_regs_live, regno)) + change_pressure (regno, true); + } + } + } + BITMAP_FREE (curr_regs_live); + + if (dump_file == NULL) + return; + + fprintf (dump_file, "\nRegister Pressure: \n"); + FOR_EACH_BB_FN (bb, cfun) + { + fprintf (dump_file, " Basic block %d: \n", bb->index); + for (i = 0; (int) i < ira_pressure_classes_num; i++) + { + enum reg_class pressure_class; + + pressure_class = ira_pressure_classes[i]; + if (BB_DATA (bb)->max_reg_pressure[pressure_class] == 0) + continue; + + fprintf (dump_file, " %s=%d\n", reg_class_names[pressure_class], + BB_DATA (bb)->max_reg_pressure[pressure_class]); + } + } + fprintf (dump_file, "\n"); +} + +/* Initialize needed resources for register pressure calculation. */ +void +regpressure_init () +{ + regstat_init_n_sets_and_refs (); + ira_set_pseudo_classes (false, dump_file); + if (flag_ira_hoist_pressure) + { + alloc_aux_for_blocks (sizeof (struct bb_data)); + calculate_bb_reg_pressure (); + } + regstat_free_n_sets_and_refs (); +} + +/* Free up all initialized resources. */ +void +regpressure_cleanup () +{ + if (flag_ira_hoist_pressure) + { + free_aux_for_blocks (); + } + free_reg_info (); +} + +/* Initialize aux data for BB regarding PRESSURE_CLASS. */ +void +regpressure_init_bb_info (basic_block bb, enum reg_class pressure_class) +{ + /* Record old information of basic block BB when it is visited + at the first time. */ + struct bb_data *data = BB_DATA (bb); + bitmap_copy (data->backup, data->live_in); + data->old_pressure = data->max_reg_pressure[pressure_class]; +} + +/* Increase PRESSURE_CLASS's register pressure in BB by NREGS. */ +void +regpressure_increase (basic_block bb, enum reg_class pressure_class, int nregs) +{ + struct bb_data *data = BB_DATA (bb); + data->max_reg_pressure[pressure_class] += nregs; +} + +/* Decrease PRESSURE_CLASS's register pressure in BB by NREGS. */ +void +regpressure_decrease (basic_block bb, enum reg_class pressure_class, int nregs) +{ + struct bb_data *data = BB_DATA (bb); + data->max_reg_pressure[pressure_class] -= nregs; +} + +/* Reset PRESSURE_CLASS's register pressure in BB to its initial value. */ +void +regpressure_reset (basic_block bb, enum reg_class pressure_class) +{ + struct bb_data *data = BB_DATA (bb); + bitmap_copy (data->live_in, data->backup); + data->max_reg_pressure[pressure_class] = data->old_pressure; +} + +/* Return TRUE if the current register pressure of PRESSURE_CLASS in BB + is less than the number of hard regs. */ +bool +regpressure_viable (basic_block bb, enum reg_class pressure_class) +{ + return (regpressure_get (bb, pressure_class) + < ira_class_hard_regs_num[pressure_class]); +} + +/* Return pressure class and number of needed hard registers (through + *NREGS) of register REGNO. */ +enum reg_class +regpressure_get_regno_pressure_class (int regno, int *nregs) +{ + if (regno >= FIRST_PSEUDO_REGISTER) + { + enum reg_class pressure_class; + + pressure_class = reg_allocno_class (regno); + pressure_class = ira_pressure_class_translate[pressure_class]; + *nregs + = ira_reg_class_max_nregs[pressure_class][PSEUDO_REGNO_MODE (regno)]; + return pressure_class; + } + else if (!TEST_HARD_REG_BIT (ira_no_alloc_regs, regno) + && !TEST_HARD_REG_BIT (eliminable_regset, regno)) + { + *nregs = 1; + return ira_pressure_class_translate[REGNO_REG_CLASS (regno)]; + } + else + { + *nregs = 0; + return NO_REGS; + } +} + +/* Return pressure class and number of hard registers (through *NREGS) + for destination of INSN. */ +enum reg_class +regpressure_get_pressure_class_and_nregs (rtx_insn *insn, int *nregs) +{ + rtx reg; + enum reg_class pressure_class; + const_rtx set = single_set_gcse (insn); + + reg = SET_DEST (set); + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + if (MEM_P (reg)) + { + *nregs = 0; + pressure_class = NO_REGS; + } + else + { + gcc_assert (REG_P (reg)); + pressure_class = reg_allocno_class (REGNO (reg)); + pressure_class = ira_pressure_class_translate[pressure_class]; + *nregs + = ira_reg_class_max_nregs[pressure_class][GET_MODE (SET_SRC (set))]; + } + return pressure_class; +} + +/* Return TRUE if REGNO is live (incoming) in BB. */ +bool +regpressure_is_live_in (basic_block bb, int regno) +{ + return bitmap_bit_p (BB_DATA (bb)->live_in, regno); +} + +/* Clear the live (incoming) bit for REGNO in BB. */ +void +regpressure_clear_live_in (basic_block bb, int regno) +{ + bitmap_clear_bit (BB_DATA (bb)->live_in, regno); +} + +/* Set the live (incoming) bit for REGNO in BB. */ +void +regpressure_set_live_in (basic_block bb, int regno) +{ + bitmap_set_bit (BB_DATA (bb)->live_in, regno); +} + +/* Returns the register pressure for PRESSURE_CLASS in BB. */ +int +regpressure_get (basic_block bb, enum reg_class pressure_class) +{ + return BB_DATA (bb)->max_reg_pressure[pressure_class]; +} + +bool +regpressure_same_class (rtx a, rtx b) +{ + enum reg_class a_class, b_class; + int a_nregs, b_nregs; + + a_class = regpressure_get_regno_pressure_class (REGNO (a), &a_nregs); + b_class = regpressure_get_regno_pressure_class (REGNO (b), &b_nregs); + + return a_class == b_class; +} diff --git a/gcc/regpressure.h b/gcc/regpressure.h new file mode 100644 index 00000000000..b9008699acd --- /dev/null +++ b/gcc/regpressure.h @@ -0,0 +1,48 @@ +/* Register pressure helper functions. + Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_REGPRESSURE_H +#define GCC_REGPRESSURE_H + +int regpressure_update_bb_reg_pressure (basic_block bb, rtx_insn *from); + +void regpressure_init (); +void regpressure_cleanup (); + +void regpressure_init_bb_info (basic_block bb, enum reg_class pressure_class); + +void regpressure_increase (basic_block bb, enum reg_class pressure_class, int nregs); +void regpressure_decrease (basic_block bb, enum reg_class pressure_class, int nregs); + +int regpressure_get (basic_block bb, enum reg_class pressure_class); + +bool regpressure_is_live_in (basic_block bb, int regno); +void regpressure_clear_live_in (basic_block bb, int regno); +void regpressure_set_live_in (basic_block bb, int regno); + +void regpressure_reset (basic_block bb, enum reg_class pressure_class); + +bool regpressure_viable (basic_block bb, enum reg_class pressure_class); + +enum reg_class regpressure_get_regno_pressure_class (int regno, int *nregs); +enum reg_class regpressure_get_pressure_class_and_nregs (rtx_insn *insn, int *nregs); + +bool regpressure_same_class (rtx a, rtx b); + +#endif -- 2.41.0