From patchwork Sun Nov 12 14:52:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 1862851 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SSwXg0Mb9z1yQy for ; Mon, 13 Nov 2023 01:53:07 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 110D03858438 for ; Sun, 12 Nov 2023 14:53:01 +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 0AB1F3858C5F for ; Sun, 12 Nov 2023 14:52:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0AB1F3858C5F 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 0AB1F3858C5F 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=1699800770; cv=none; b=aaOEmeSIRT2h7KdiW16CGLfrOUo+IlDoNCOXdvF9BFUGboIXnrZdl+8fr0f44WzWyIUwaFH9sXAS86Yk0mc5j9uh3yNgTxZDsJo8qS/3ODFCn49GHShXSKWfNkmj0mUEq1riN8QTZDV+0nbhgoOj7mUNetPLSHTTPgPYbdi6qq0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699800770; c=relaxed/simple; bh=CZnZj+uCH/tj3n6AMPAjpeRQdDCInH/EoEi3SV5AepM=; h=From:To:Subject:Date:Message-Id:MIME-Version; b=ZUiXT/5vJwHMtswKofEqmtGqF0RTQZD6yyc3mci9K+hxyvUpkS0OYiDxrGcDR+lznew0p8PRjOznM04pL3E8ul2JIrR5LVO25750fcwX+edQnHJlytJeilp3txBax5l9FK5xFxppoUFE1Fb7rodczYW+cTnMrZuW71C1oWwTs5I= 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 971A3DA7; Sun, 12 Nov 2023 06:53:31 -0800 (PST) Received: from e121540-lin.manchester.arm.com (e121540-lin.manchester.arm.com [10.32.110.72]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id B894A3F7B4; Sun, 12 Nov 2023 06:52:45 -0800 (PST) From: Richard Sandiford To: jlaw@ventanamicro.com, vmakarov@redhat.com, gcc-patches@gcc.gnu.org Cc: Richard Sandiford Subject: [PATCH 1/5] Add register filter operand to define_register_constraint Date: Sun, 12 Nov 2023 14:52:25 +0000 Message-Id: <20231112145229.2924713-2-richard.sandiford@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231112145229.2924713-1-richard.sandiford@arm.com> References: <20231112145229.2924713-1-richard.sandiford@arm.com> 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+incoming=patchwork.ozlabs.org@gcc.gnu.org The main way of enforcing registers to be aligned is through HARD_REGNO_MODE_OK. But this is a global property that applies to all operands. A given (regno, mode) pair is either globally valid or globally invalid. This patch instead adds a way of specifying that individual operands must be aligned. More generally, it allows constraints to specify a C++ condition that the operand's REGNO must satisfy. The condition must be invariant for a given set of target options, so that it can be precomputed and cached as a HARD_REG_SET. This information will be used in very compile-time-sensitive parts of the compiler. A lot of the complication is in allowing the information to be stored and tested without much memory cost, and without impacting targets that don't use the feature. Specifically: - Constraints are encouraged to test the absolute REGNO rather than an offset from the start of the containing class. For example, all constraints for even registers should use the same condition, such as "regno % 2 == 0". This requires the classes to start at even register boundaries, but that's already an implicit requirement due to things like the ira-costs.cc code that begins: /* Some targets allow pseudos to be allocated to unaligned sequences of hard registers. However, selecting an unaligned sequence can unnecessarily restrict later allocations. So increase the cost of unaligned hard regs to encourage the use of aligned hard regs. */ - Each unique condition is given a "filter identifier". - The total number of filters is given by NUM_REGISTER_FILTERS, defined automatically in insn-config.h. Structures can therefore use a bitfield of NUM_REGISTER_FILTERS to represent a mask of filters. - There is a new target global, target_constraints, that caches the HARD_REG_SET for each filter. - There is a function for looking up the HARD_REG_SET filter for a given constraint and one for looking up the filter id. Both simply return a constant on targets that don't use the feature. - There are functions for testing a register against a specific filter, or against a mask of filters. This patch just adds the information. Later ones make use of it. gcc/ * rtl.def (DEFINE_REGISTER_CONSTRAINT): Add an optional filter operand. * doc/md.texi (define_register_constraint): Document it. * doc/tm.texi.in: Reference it in discussion about aligned registers. * doc/tm.texi: Regenerate. * gensupport.h (register_filters, get_register_filter_id): Declare. * gensupport.cc (register_filter_map, register_filters): New variables. (get_register_filter_id): New function. (process_define_register_constraint): Likewise. (process_rtx): Pass define_register_constraints to process_define_register_constraint. * genconfig.cc (main): Emit a definition of NUM_REGISTER_FILTERS. * genpreds.cc (constraint_data): Add a filter field. (add_constraint): Update accordingly. (process_define_register_constraint): Pass the filter operand. (write_init_reg_class_start_regs): New function. (write_get_register_filter): Likewise. (write_get_register_filter_id): Likewise. (write_tm_preds_h): Write a definition of target_constraints, plus helpers to test its contents. Write the get_register_filter* functions. (write_insn_preds_c): Write init_reg_class_start_regs. * reginfo.cc (init_reg_class_start_regs): Declare. (init_reg_sets): Call it. * target-globals.h (this_target_constraints): Declare. (target_globals): Add a constraints field. (restore_target_globals): Update accordingly. * target-globals.cc: Include tm_p.h. (default_target_globals): Initialize the constraints field. (save_target_globals): Handle the constraints field. (target_globals::~target_globals): Likewise. --- gcc/doc/md.texi | 41 +++++++++++- gcc/doc/tm.texi | 3 +- gcc/doc/tm.texi.in | 3 +- gcc/genconfig.cc | 2 + gcc/genpreds.cc | 146 +++++++++++++++++++++++++++++++++++++++++- gcc/gensupport.cc | 48 +++++++++++++- gcc/gensupport.h | 3 + gcc/reginfo.cc | 5 ++ gcc/rtl.def | 6 +- gcc/target-globals.cc | 6 +- gcc/target-globals.h | 3 + 11 files changed, 254 insertions(+), 12 deletions(-) diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 5d86152e5dd..dc8c068646d 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -4513,8 +4513,8 @@ Register constraints correspond directly to register classes. @xref{Register Classes}. There is thus not much flexibility in their definitions. -@deffn {MD Expression} define_register_constraint name regclass docstring -All three arguments are string constants. +@deffn {MD Expression} define_register_constraint name regclass docstring [filter] +All arguments are string constants. @var{name} is the name of the constraint, as it will appear in @code{match_operand} expressions. If @var{name} is a multi-letter constraint its length shall be the same for all constraints starting @@ -4526,6 +4526,43 @@ look at the operand. The usual use of expressions is to map some register constraints to @code{NO_REGS} when the register class is not available on a given subarchitecture. +If an operand occupies multiple hard registers, the constraint +requires all of those registers to belong to @var{regclass}. +For example, if @var{regclass} is @code{GENERAL_REGS} and +@code{GENERAL_REGS} contains registers @code{r0} to @code{r15}, +the constraint does not allow @var{r15} to be used for modes +that occupy more than one register. + +@cindex @code{TARGET_HARD_REGNO_MODE_OK} and constraints +The choice of register is also constrained by @code{TARGET_HARD_REGNO_MODE_OK}. +For example, if @code{TARGET_HARD_REGNO_MODE_OK} disallows @samp{(reg:DI r1)}, +that requirement applies to all constraints whose classes include @code{r1}. + +However, it is sometimes useful to impose extra operand-specific +requirements on the register number. For example, a target might not +want to prevent @emph{all} odd-even pairs from holding @code{DImode} +values, but it might still need to prevent specific operands from +having an odd-numbered register. The optional @var{filter} argument +exists for such cases. When given, @var{filter} is a C++ expression +that evaluates to true if @code{regno} is a valid register for the +operand. If an operand occupies multiple registers, the condition +applies only to the first register. + +For example: + +@smallexample +(define_register_constraint "e" "GENERAL_REGS" "..." "regno % 2 == 0") +@end smallexample + +defines a constraint that requires an even-numbered general register. + +Filter conditions that impose an alignment are encouraged to test +the alignment of @code{regno} itself, as in the example, rather than +calculate an offset relative to the start of the class. If it is +sometimes necessary for a register of class @var{c} to be aligned +to @var{n}, the first register in @var{c} should itself by divisible +by @var{n}. + @var{docstring} is a sentence documenting the meaning of the constraint. Docstrings are explained further below. @end deffn diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index abc23b2bb73..b13b5161161 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -2478,7 +2478,8 @@ When a value occupying several consecutive registers is expected in a certain class, all the registers used must belong to that class. Therefore, register classes cannot be used to enforce a requirement for a register pair to start with an even-numbered register. The way to -specify this requirement is with @code{TARGET_HARD_REGNO_MODE_OK}. +specify this requirement is with @code{TARGET_HARD_REGNO_MODE_OK}, +or with a filter expression in a @code{define_register_constraint}. Register classes used for input-operands of bitwise-and or shift instructions have a special requirement: each such class must have, for diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 3d3ae12cc2f..9a92cb97337 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -2060,7 +2060,8 @@ When a value occupying several consecutive registers is expected in a certain class, all the registers used must belong to that class. Therefore, register classes cannot be used to enforce a requirement for a register pair to start with an even-numbered register. The way to -specify this requirement is with @code{TARGET_HARD_REGNO_MODE_OK}. +specify this requirement is with @code{TARGET_HARD_REGNO_MODE_OK}, +or with a filter expression in a @code{define_register_constraint}. Register classes used for input-operands of bitwise-and or shift instructions have a special requirement: each such class must have, for diff --git a/gcc/genconfig.cc b/gcc/genconfig.cc index 2ee323f80c3..c8c2ebef21c 100644 --- a/gcc/genconfig.cc +++ b/gcc/genconfig.cc @@ -360,6 +360,8 @@ main (int argc, const char **argv) printf ("#define MAX_INSNS_PER_PEEP2 0\n"); } + printf ("#define NUM_REGISTER_FILTERS %d\n", register_filters.length ()); + puts ("\n#endif /* GCC_INSN_CONFIG_H */"); if (ferror (stdout) || fflush (stdout) || fclose (stdout)) diff --git a/gcc/genpreds.cc b/gcc/genpreds.cc index bdd65ef7d7a..5535a7512fb 100644 --- a/gcc/genpreds.cc +++ b/gcc/genpreds.cc @@ -677,6 +677,7 @@ public: size_t namelen; const char *regclass; /* for register constraints */ rtx exp; /* for other constraints */ + const char *filter; /* the register filter condition, or null if none */ unsigned int is_register : 1; unsigned int is_const_int : 1; unsigned int is_const_dbl : 1; @@ -763,7 +764,8 @@ mangle (const char *name) is the register class, if any; EXP is the expression to test, if any; IS_MEMORY, IS_SPECIAL_MEMORY, IS_RELAXED_MEMORY and IS_ADDRESS indicate memory, special memory, and address constraints, respectively; LOC is the .md - file location. + file location; FILTER is the filter condition for a register constraint, + or null if none. Not all combinations of arguments are valid; most importantly, REGCLASS is mutually exclusive with EXP, and @@ -776,7 +778,8 @@ mangle (const char *name) static void add_constraint (const char *name, const char *regclass, rtx exp, bool is_memory, bool is_special_memory, - bool is_relaxed_memory, bool is_address, file_location loc) + bool is_relaxed_memory, bool is_address, file_location loc, + const char *filter = nullptr) { class constraint_data *c, **iter, **slot; const char *p; @@ -908,6 +911,7 @@ add_constraint (const char *name, const char *regclass, c->namelen = namelen; c->regclass = regclass; c->exp = exp; + c->filter = filter; c->is_register = regclass != 0; c->is_const_int = is_const_int; c->is_const_dbl = is_const_dbl; @@ -966,7 +970,8 @@ static void process_define_register_constraint (md_rtx_info *info) { add_constraint (XSTR (info->def, 0), XSTR (info->def, 1), - 0, false, false, false, false, info->loc); + 0, false, false, false, false, info->loc, + XSTR (info->def, 3)); } /* Put the constraints into enum order. We want to keep constraints @@ -1319,6 +1324,34 @@ write_insn_const_int_ok_for_constraint (void) " return false;\n" "}\n"); } + +/* Print the init_reg_class_start_regs function, which initializes + this_target_constraints->register_filters from the C conditions + in the define_register_constraints. */ +static void +write_init_reg_class_start_regs () +{ + printf ("\n" + "void\n" + "init_reg_class_start_regs ()\n" + "{\n"); + if (!register_filters.is_empty ()) + { + printf (" for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER;" + " ++regno)\n" + " {\n"); + for (unsigned int i = 0; i < register_filters.length (); ++i) + { + printf (" if ("); + rtx_reader_ptr->print_c_condition (register_filters[i]); + printf (")\n" + " SET_HARD_REG_BIT (%s[%d], regno);\n", + "this_target_constraints->register_filters", i); + } + printf (" }\n"); + } + printf ("}\n"); +} /* Write a definition for a function NAME that returns true if a given constraint_num is in the range [START, END). */ @@ -1401,6 +1434,54 @@ print_type_tree (const vec > &vec, printf ("%*sreturn %s;\n", indent, "", fallback); } +/* Print the get_register_filter function, which returns a pointer + to the start register filter for a given constraint, or null if none. */ +static void +write_get_register_filter () +{ + constraint_data *c; + + printf ("\n" + "#ifdef GCC_HARD_REG_SET_H\n" + "static inline const HARD_REG_SET *\n" + "get_register_filter (constraint_num%s)\n", + register_filters.is_empty () ? "" : " c"); + printf ("{\n"); + FOR_ALL_CONSTRAINTS (c) + if (c->is_register && c->filter) + { + printf (" if (c == CONSTRAINT_%s)\n", c->c_name); + printf (" return &this_target_constraints->register_filters[%d];\n", + get_register_filter_id (c->filter)); + } + printf (" return nullptr;\n" + "}\n" + "#endif\n"); +} + +/* Print the get_register_filter_id function, which returns the index + of the given constraint's register filter in + this_target_constraints->register_filters, or -1 if none. */ +static void +write_get_register_filter_id () +{ + constraint_data *c; + + printf ("\n" + "static inline int\n" + "get_register_filter_id (constraint_num%s)\n", + register_filters.is_empty () ? "" : " c"); + printf ("{\n"); + FOR_ALL_CONSTRAINTS (c) + if (c->is_register && c->filter) + { + printf (" if (c == CONSTRAINT_%s)\n", c->c_name); + printf (" return %d;\n", get_register_filter_id (c->filter)); + } + printf (" return -1;\n" + "}\n"); +} + /* Write tm-preds.h. Unfortunately, it is impossible to forward-declare an enumeration in portable C, so we have to condition all these prototypes on HAVE_MACHINE_MODES. */ @@ -1425,6 +1506,53 @@ write_tm_preds_h (void) puts ("#endif /* HAVE_MACHINE_MODES */\n"); + /* Print the definition of the target_constraints structure. */ + printf ("#ifdef GCC_HARD_REG_SET_H\n" + "struct target_constraints {\n" + " HARD_REG_SET register_filters[%d];\n", + MAX (register_filters.length (), 1)); + printf ("};\n" + "\n" + "extern struct target_constraints default_target_constraints;\n" + "#if SWITCHABLE_TARGET\n" + "extern struct target_constraints *this_target_constraints;\n" + "#else\n" + "#define this_target_constraints (&default_target_constraints)\n" + "#endif\n"); + + /* Print TEST_REGISTER_FILTER_BIT, which tests whether register REGNO + is a valid start register for register filter ID. */ + printf ("\n" + "#define TEST_REGISTER_FILTER_BIT(ID, REGNO) \\\n"); + if (register_filters.is_empty ()) + printf (" ((void) (ID), (void) (REGNO), false)\n"); + else + printf (" TEST_HARD_REG_BIT (" + "this_target_constraints->register_filters[ID], REGNO)\n"); + + /* Print test_register_filters, which tests whether register REGNO + is a valid start register for the mask of register filters in MASK. */ + printf ("\n" + "inline bool\n" + "test_register_filters (unsigned int%s, unsigned int%s)\n", + register_filters.is_empty () ? "" : " mask", + register_filters.is_empty () ? "" : " regno"); + printf ("{\n"); + if (register_filters.is_empty ()) + printf (" return true;\n"); + else + { + printf (" for (unsigned int id = 0; id < %d; ++id)\n", + register_filters.length ()); + printf (" if ((mask & (1U << id))\n" + "\t&& !TEST_REGISTER_FILTER_BIT (id, regno))\n" + " return false;\n" + " return true;\n"); + } + printf ("}\n" + "#endif\n" + "\n"); + if (constraint_max_namelen > 0) { write_enum_constraint_num (); @@ -1548,6 +1676,9 @@ write_tm_preds_h (void) values.safe_push (std::make_pair (address_end, "CT_FIXED_FORM")); print_type_tree (values, 0, values.length (), "CT_REGISTER", 2); puts ("}"); + + write_get_register_filter (); + write_get_register_filter_id (); } puts ("#endif /* tm-preds.h */"); @@ -1599,6 +1730,13 @@ write_insn_preds_c (void) #include \"tm-constrs.h\"\n\ #include \"target.h\"\n"); + printf ("\n" + "struct target_constraints default_target_constraints;\n" + "#if SWITCHABLE_TARGET\n" + "struct target_constraints *this_target_constraints" + " = &default_target_constraints;\n" + "#endif\n"); + FOR_ALL_PREDICATES (p) write_one_predicate_function (p); @@ -1613,6 +1751,8 @@ write_insn_preds_c (void) if (have_const_int_constraints) write_insn_const_int_ok_for_constraint (); } + + write_init_reg_class_start_regs (); } /* Argument parsing. */ diff --git a/gcc/gensupport.cc b/gcc/gensupport.cc index 688808c7d12..0ac0d0772d4 100644 --- a/gcc/gensupport.cc +++ b/gcc/gensupport.cc @@ -400,6 +400,45 @@ process_define_predicate (rtx desc, file_location loc) #undef I #undef N #undef Y + +/* Maps register filter conditions to the associated filter identifier. */ +static hash_map register_filter_map; + +/* All register filter conditions, indexed by identifier. */ +vec register_filters; + +/* Return the unique identifier for filter condition FILTER. Identifiers + are assigned automatically when the define_register_constraint is + parsed. */ + +unsigned int +get_register_filter_id (const char *filter) +{ + unsigned int *slot = register_filter_map.get (filter); + gcc_assert (slot); + return *slot; +} + +/* Process define_register_constraint directive DESC, at location LOC. */ + +static void +process_define_register_constraint (rtx desc, file_location loc) +{ + /* Assign identifiers to each unique register filter condition. */ + if (const char *filter = XSTR (desc, 3)) + { + bool existed = false; + unsigned int &id = register_filter_map.get_or_insert (filter, &existed); + if (!existed) + { + id = register_filters.length (); + if (id == 32) + fatal_at (loc, "too many distinct register filters, maximum" + " is 32"); + register_filters.safe_push (filter); + } + } +} /* Queue PATTERN on LIST_TAIL. Return the address of the new queue element. */ @@ -1075,10 +1114,15 @@ process_rtx (rtx desc, file_location loc) case DEFINE_PREDICATE: case DEFINE_SPECIAL_PREDICATE: process_define_predicate (desc, loc); - /* Fall through. */ + queue_pattern (desc, &define_pred_tail, loc); + break; - case DEFINE_CONSTRAINT: case DEFINE_REGISTER_CONSTRAINT: + process_define_register_constraint (desc, loc); + queue_pattern (desc, &define_pred_tail, loc); + break; + + case DEFINE_CONSTRAINT: case DEFINE_MEMORY_CONSTRAINT: case DEFINE_SPECIAL_MEMORY_CONSTRAINT: case DEFINE_RELAXED_MEMORY_CONSTRAINT: diff --git a/gcc/gensupport.h b/gcc/gensupport.h index 7396118714b..27e8444a745 100644 --- a/gcc/gensupport.h +++ b/gcc/gensupport.h @@ -108,6 +108,9 @@ struct optab_def extern optab_def optabs[]; extern unsigned int num_optabs; +extern vec register_filters; +extern unsigned int get_register_filter_id (const char *); + /* Information about an instruction name that matches an optab pattern. */ struct optab_pattern { diff --git a/gcc/reginfo.cc b/gcc/reginfo.cc index d472a35946a..5b6e706b35d 100644 --- a/gcc/reginfo.cc +++ b/gcc/reginfo.cc @@ -140,6 +140,9 @@ reginfo_cc_finalize (void) CLEAR_HARD_REG_SET (global_reg_set); } +/* In insn-preds.cc. */ +extern void init_reg_class_start_regs (); + /* Given a register bitmap, turn on the bits in a HARD_REG_SET that correspond to the hard registers, if any, set in that map. This could be done far more efficiently by having all sorts of special-cases @@ -198,6 +201,8 @@ init_reg_sets (void) SET_HARD_REG_SET (accessible_reg_set); SET_HARD_REG_SET (operand_reg_set); + + init_reg_class_start_regs (); } /* We need to save copies of some of the register information which diff --git a/gcc/rtl.def b/gcc/rtl.def index 88e2b198503..a40e1a7bb18 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -1016,8 +1016,10 @@ DEF_RTL_EXPR(DEFINE_SPECIAL_PREDICATE, "define_special_predicate", "ses", RTX_EX at -m switches and the like. 2: A docstring for this constraint, in Texinfo syntax; not currently used, in future will be incorporated into the manual's list of - machine-specific operand constraints. */ -DEF_RTL_EXPR(DEFINE_REGISTER_CONSTRAINT, "define_register_constraint", "sss", RTX_EXTRA) + machine-specific operand constraints. + 3: A C expression that evalutes to true if "regno" is a valid + start register. */ +DEF_RTL_EXPR(DEFINE_REGISTER_CONSTRAINT, "define_register_constraint", "sssS", RTX_EXTRA) /* Definition of a non-register operand constraint. These look at the operand and decide whether it fits the constraint. diff --git a/gcc/target-globals.cc b/gcc/target-globals.cc index 81244b127fc..cfa0045e02c 100644 --- a/gcc/target-globals.cc +++ b/gcc/target-globals.cc @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see #include "bb-reorder.h" #include "lower-subreg.h" #include "function-abi.h" +#include "tm_p.h" #if SWITCHABLE_TARGET class target_globals default_target_globals = { @@ -60,7 +61,8 @@ class target_globals default_target_globals = { &default_target_builtins, &default_target_gcse, &default_target_bb_reorder, - &default_target_lower_subreg + &default_target_lower_subreg, + &default_target_constraints }; class target_globals * @@ -84,6 +86,7 @@ save_target_globals (void) g->gcse = XCNEW (struct target_gcse); g->bb_reorder = XCNEW (struct target_bb_reorder); g->lower_subreg = XCNEW (struct target_lower_subreg); + g->constraints = XCNEW (target_constraints); restore_target_globals (g); init_reg_sets (); target_reinit (); @@ -141,6 +144,7 @@ target_globals::~target_globals () XDELETE (gcse); XDELETE (bb_reorder); XDELETE (lower_subreg); + XDELETE (constraints); } } diff --git a/gcc/target-globals.h b/gcc/target-globals.h index daedf66017f..42f082c589c 100644 --- a/gcc/target-globals.h +++ b/gcc/target-globals.h @@ -38,6 +38,7 @@ extern struct target_builtins *this_target_builtins; extern struct target_gcse *this_target_gcse; extern struct target_bb_reorder *this_target_bb_reorder; extern struct target_lower_subreg *this_target_lower_subreg; +extern struct target_constraints *this_target_constraints; #endif class GTY(()) target_globals { @@ -61,6 +62,7 @@ public: struct target_gcse *GTY((skip)) gcse; struct target_bb_reorder *GTY((skip)) bb_reorder; struct target_lower_subreg *GTY((skip)) lower_subreg; + struct target_constraints *GTY((skip)) constraints; }; #if SWITCHABLE_TARGET @@ -89,6 +91,7 @@ restore_target_globals (class target_globals *g) this_target_gcse = g->gcse; this_target_bb_reorder = g->bb_reorder; this_target_lower_subreg = g->lower_subreg; + this_target_constraints = g->constraints; } #endif From patchwork Sun Nov 12 14:52:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 1862852 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SSwXn1tJjz1yQy for ; Mon, 13 Nov 2023 01:53:13 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3A2E138582A4 for ; Sun, 12 Nov 2023 14:53:11 +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 B3E973858426 for ; Sun, 12 Nov 2023 14:52:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B3E973858426 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 B3E973858426 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=1699800780; cv=none; b=mzRRdXGC08i5qADqTZ0kyhIq19+D7lYKSJMwe6talk8mBrCSLjHL/UHMjj9Wi8rNc4FDvme7lkHImhmXjxtVqEqT4ZkSGjs1O+x7DdDn4yKF4jnQBN6uQiBZBlr4sSuM5p0zjoDMJ+RcBRE2EXRl22ZhA6lnxup8L/qoCRs4/Bs= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699800780; c=relaxed/simple; bh=Xp00aMKO5S31PkxEgyRjWAmBmBhg9EZx3tsF+XijYxU=; h=From:To:Subject:Date:Message-Id:MIME-Version; b=DzdQ0y0I7YAtc8AXfQ/QiaD2dbW7I+8ASZfyf8yI+bSIskFcYQ/5qodpHcWjnEPg6jV+EUbUgFqI/+cbAVeO/QYgF3yAXNVgLLffo3mWFUVF0SdbslFv2uPUu4PMnZ6XkQJJsSL4vzndJ4G+3tIBeT6szCWIz6H2m+6vv+AzRZY= 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 6C017DA7; Sun, 12 Nov 2023 06:53:43 -0800 (PST) Received: from e121540-lin.manchester.arm.com (e121540-lin.manchester.arm.com [10.32.110.72]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id C47173F7B4; Sun, 12 Nov 2023 06:52:57 -0800 (PST) From: Richard Sandiford To: jlaw@ventanamicro.com, vmakarov@redhat.com, gcc-patches@gcc.gnu.org Cc: Richard Sandiford Subject: [PATCH 2/5] recog: Handle register filters Date: Sun, 12 Nov 2023 14:52:26 +0000 Message-Id: <20231112145229.2924713-3-richard.sandiford@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231112145229.2924713-1-richard.sandiford@arm.com> References: <20231112145229.2924713-1-richard.sandiford@arm.com> 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+incoming=patchwork.ozlabs.org@gcc.gnu.org The main (but simplest) part of this patch makes constrain_operands take register filters into account. The rest of the patch adds register filter information to operand_alternative. Generally, if two register constraints have different register filters, it's better if they're in separate alternatives. However, the syntax doesn't enforce that, and we can't assert it due to inline asms. So it's a choice between (a) adding code to enforce consistent filters or (b) dealing with mixes of filters in a conservatively correct way (in the sense of not allowing invalid operands). The latter seems much easier. The patch therefore adds a mask of the filters that apply to at least one constraint in a given operand alternative. A register is OK if it passes all of the filters in the mask. gcc/ * recog.h (operand_alternative): Add a register_filters field. (alternative_register_filters): New function. * recog.cc (preprocess_constraints): Calculate the filters field. (constrain_operands): Check register filters. --- gcc/recog.cc | 14 ++++++++++++-- gcc/recog.h | 24 ++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/gcc/recog.cc b/gcc/recog.cc index 3bd2d73c259..eaab79c25d7 100644 --- a/gcc/recog.cc +++ b/gcc/recog.cc @@ -2857,6 +2857,7 @@ preprocess_constraints (int n_operands, int n_alternatives, for (j = 0; j < n_alternatives; j++, op_alt += n_operands) { op_alt[i].cl = NO_REGS; + op_alt[i].register_filters = 0; op_alt[i].constraint = p; op_alt[i].matches = -1; op_alt[i].matched = -1; @@ -2919,7 +2920,12 @@ preprocess_constraints (int n_operands, int n_alternatives, case CT_REGISTER: cl = reg_class_for_constraint (cn); if (cl != NO_REGS) - op_alt[i].cl = reg_class_subunion[op_alt[i].cl][cl]; + { + op_alt[i].cl = reg_class_subunion[op_alt[i].cl][cl]; + auto filter_id = get_register_filter_id (cn); + if (filter_id >= 0) + op_alt[i].register_filters |= 1U << filter_id; + } break; case CT_CONST_INT: @@ -3219,13 +3225,17 @@ constrain_operands (int strict, alternative_mask alternatives) enum reg_class cl = reg_class_for_constraint (cn); if (cl != NO_REGS) { + auto *filter = get_register_filter (cn); if (strict < 0 || (strict == 0 && REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER) || (strict == 0 && GET_CODE (op) == SCRATCH) || (REG_P (op) - && reg_fits_class_p (op, cl, offset, mode))) + && reg_fits_class_p (op, cl, offset, mode) + && (!filter + || TEST_HARD_REG_BIT (*filter, + REGNO (op) + offset)))) win = true; } diff --git a/gcc/recog.h b/gcc/recog.h index c6ef619c5dd..5c801e7bb81 100644 --- a/gcc/recog.h +++ b/gcc/recog.h @@ -42,6 +42,7 @@ enum op_type { OP_INOUT }; +#ifndef GENERATOR_FILE struct operand_alternative { /* Pointer to the beginning of the constraint string for this alternative, @@ -62,6 +63,11 @@ struct operand_alternative matches this one. */ int matched : 8; + /* Bit ID is set if the constraint string includes a register constraint with + register filter ID. Use test_register_filters (REGISTER_FILTERS, REGNO) + to test whether REGNO is a valid start register for the operand. */ + unsigned int register_filters : MAX (NUM_REGISTER_FILTERS, 1); + /* Nonzero if '&' was found in the constraint string. */ unsigned int earlyclobber : 1; /* Nonzero if TARGET_MEM_CONSTRAINT was found in the constraint @@ -72,8 +78,6 @@ struct operand_alternative /* Nonzero if 'X' was found in the constraint string, or if the constraint string for this alternative was empty. */ unsigned int anything_ok : 1; - - unsigned int unused : 12; }; /* Return the class for operand I of alternative ALT, taking matching @@ -85,6 +89,18 @@ alternative_class (const operand_alternative *alt, int i) return alt[i].matches >= 0 ? alt[alt[i].matches].cl : alt[i].cl; } +/* Return the mask of register filters that should be applied to operand I + of alternative ALT, taking matching constraints into account. */ + +inline unsigned int +alternative_register_filters (const operand_alternative *alt, int i) +{ + return (alt[i].matches >= 0 + ? alt[alt[i].matches].register_filters + : alt[i].register_filters); +} +#endif + /* A class for substituting one rtx for another within an instruction, or for recursively simplifying the instruction as-is. Derived classes can record or filter certain decisions. */ @@ -242,9 +258,11 @@ extern void extract_insn (rtx_insn *); extern void extract_constrain_insn (rtx_insn *insn); extern void extract_constrain_insn_cached (rtx_insn *); extern void extract_insn_cached (rtx_insn *); +#ifndef GENERATOR_FILE extern void preprocess_constraints (int, int, const char **, operand_alternative *, rtx **); extern const operand_alternative *preprocess_insn_constraints (unsigned int); +#endif extern void preprocess_constraints (rtx_insn *); extern rtx_insn *peep2_next_insn (int); extern bool peep2_regno_dead_p (int, int); @@ -380,6 +398,7 @@ struct recog_data_d extern struct recog_data_d recog_data; +#ifndef GENERATOR_FILE extern const operand_alternative *recog_op_alt; /* Return a pointer to an array in which index OP describes the constraints @@ -393,6 +412,7 @@ which_op_alt () recog_data.n_alternatives - 1)); return &recog_op_alt[which_alternative * recog_data.n_operands]; } +#endif /* A table defined in insn-output.cc that give information about each insn-code value. */ From patchwork Sun Nov 12 14:52:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 1862853 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SSwXz3LkLz1yRf for ; Mon, 13 Nov 2023 01:53:23 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0D974385841B for ; Sun, 12 Nov 2023 14:53:21 +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 CC00F38582BC for ; Sun, 12 Nov 2023 14:53:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CC00F38582BC 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 CC00F38582BC 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=1699800790; cv=none; b=ZqGsE1UxGZU174cs426wJ6PkI7vlaW2ZVNF1Ffo8uPndIN3vRZBHjMbjV6sxjutsccIfA3PWNR+2ANT8yttHrAHF2nF0UqmeKPH9ZkEPZOUOnHf8nI7DmJbb9Ml6bTq8Y7sHTuRkpyQ65BsnUtZRIJZ9kaJU7Ae2p/4GI4gd74E= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699800790; c=relaxed/simple; bh=cLE3KAVdm3xeh1pzjMEQyHkolsgrcF12VEzLAHeNM/o=; h=From:To:Subject:Date:Message-Id:MIME-Version; b=M6PxjJRN9reV9I+DschutyRhcXqaBhhpECQOgP9tj2FDy/7DRytxOaSXYeI7YiCIF3DFQzF1nbdaNA6E4N+9MPijt/nroUartwoU9D7l7KS045x5jk1r3LOmxyBkxK9gcYWb38ocXNwPy8W/+8npjK0L84tra9fW+SH9AceqRaQ= 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 8780BDA7; Sun, 12 Nov 2023 06:53:54 -0800 (PST) Received: from e121540-lin.manchester.arm.com (e121540-lin.manchester.arm.com [10.32.110.72]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id DFA843F7B4; Sun, 12 Nov 2023 06:53:08 -0800 (PST) From: Richard Sandiford To: jlaw@ventanamicro.com, vmakarov@redhat.com, gcc-patches@gcc.gnu.org Cc: Richard Sandiford Subject: [PATCH 3/5] lra: Handle register filters Date: Sun, 12 Nov 2023 14:52:27 +0000 Message-Id: <20231112145229.2924713-4-richard.sandiford@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231112145229.2924713-1-richard.sandiford@arm.com> References: <20231112145229.2924713-1-richard.sandiford@arm.com> 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+incoming=patchwork.ozlabs.org@gcc.gnu.org This patch makes LRA apply register filters. This plus the recog change is enough for correct code generation, but a follow-on IRA patch improves the allocation. All the new code should be optimised away on targets that don't use register filters. That's because get_register_filter just wraps "return nullptr" on those targets. gcc/ * lra-constraints.cc (process_alt_operands): Check register filters. --- gcc/lra-constraints.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc index 0607c8be7cb..9b6a2af5b75 100644 --- a/gcc/lra-constraints.cc +++ b/gcc/lra-constraints.cc @@ -2149,6 +2149,7 @@ process_alt_operands (int only_alternative) int reload_nregs, reload_sum; bool costly_p; enum reg_class cl; + const HARD_REG_SET *cl_filter; /* Calculate some data common for all alternatives to speed up the function. */ @@ -2514,6 +2515,7 @@ process_alt_operands (int only_alternative) || spilled_pseudo_p (op)) win = true; cl = GENERAL_REGS; + cl_filter = nullptr; goto reg; default: @@ -2523,7 +2525,10 @@ process_alt_operands (int only_alternative) case CT_REGISTER: cl = reg_class_for_constraint (cn); if (cl != NO_REGS) - goto reg; + { + cl_filter = get_register_filter (cn); + goto reg; + } break; case CT_CONST_INT: @@ -2567,6 +2572,7 @@ process_alt_operands (int only_alternative) win = true; cl = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, ADDRESS, SCRATCH); + cl_filter = nullptr; badop = false; goto reg; @@ -2600,6 +2606,8 @@ process_alt_operands (int only_alternative) this_alternative_exclude_start_hard_regs |= ira_exclude_class_mode_regs[cl][mode]; this_alternative_set |= reg_class_contents[cl]; + if (cl_filter) + this_alternative_exclude_start_hard_regs |= ~*cl_filter; if (costly_p) { this_costly_alternative @@ -2613,6 +2621,9 @@ process_alt_operands (int only_alternative) if (hard_regno[nop] >= 0 && in_hard_reg_set_p (this_alternative_set, mode, hard_regno[nop]) + && (!cl_filter + || TEST_HARD_REG_BIT (*cl_filter, + hard_regno[nop])) && ((REG_ATTRS (op) && (decl = REG_EXPR (op)) != NULL && VAR_P (decl) && DECL_HARD_REGISTER (decl)) || !(TEST_HARD_REG_BIT From patchwork Sun Nov 12 14:52:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 1862854 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SSwYB6wZwz1yQy for ; Mon, 13 Nov 2023 01:53:34 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id EDD9D3858296 for ; Sun, 12 Nov 2023 14:53:32 +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 14E2D3858028 for ; Sun, 12 Nov 2023 14:53:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 14E2D3858028 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 14E2D3858028 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=1699800803; cv=none; b=mALZHiAFUXuUC7WZGr3acI7HgcC6Rpm5UtCSSuRcB4Z5tXWXUMAsQqKiowljUw4nrl7VqmZxOfMCgkOkk0/r6FNQnvQqydP1mW3dQzJSPWianV7UrMQy7hDRxb0bDcSj4eA6Hue/KHfQHUTBd3PgRsCwkCVVpNaN11lpVWQqFJk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699800803; c=relaxed/simple; bh=vHwyfg7WtyVqkpVCvO1zoqr6Yhyd4uYtWtsFWg+DqEY=; h=From:To:Subject:Date:Message-Id:MIME-Version; b=iSLqXVtOQQIhN0iSQOEER8l51GfSj/wwXa+BhAXisQJBvxD+lxAiHpw4jQoIe1sIgcIrgXq6YdK0oHBe0mNaeZne7WLvN3yB+BGpcoznKdcr29a8lEPpT9p/huVTKIqpV6oFFyqJtbfePIOhi38gzWdXCufZeiBqlYhke2OiWBY= 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 93063DA7; Sun, 12 Nov 2023 06:54:05 -0800 (PST) Received: from e121540-lin.manchester.arm.com (e121540-lin.manchester.arm.com [10.32.110.72]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id EB4493F7B4; Sun, 12 Nov 2023 06:53:19 -0800 (PST) From: Richard Sandiford To: jlaw@ventanamicro.com, vmakarov@redhat.com, gcc-patches@gcc.gnu.org Cc: Richard Sandiford Subject: [PATCH 4/5] ira: Handle register filters Date: Sun, 12 Nov 2023 14:52:28 +0000 Message-Id: <20231112145229.2924713-5-richard.sandiford@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231112145229.2924713-1-richard.sandiford@arm.com> References: <20231112145229.2924713-1-richard.sandiford@arm.com> 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+incoming=patchwork.ozlabs.org@gcc.gnu.org This patch makes IRA apply register filters when picking hard registers. All the new code should be optimised away on targets that don't use register filters. On targets that do use them, the new register_filters bitfield is expected to be only a handful of bits. Information about register filters is recorded in process_bb_node_lives. The information isn't really related to liveness, but it's a convenient point because (a) we've already built the allocno structures and (b) we've already extracted the insn and preprocessed the constraints. gcc/ * ira-int.h (ira_allocno): Add a register_filters field. (ALLOCNO_REGISTER_FILTERS): New macro. (ALLOCNO_SET_REGISTER_FILTERS): Likewise. * ira-build.cc (ira_create_allocno): Initialize register_filters. (create_cap_allocno): Propagate register_filters. (propagate_allocno_info): Likewise. (propagate_some_info_from_allocno): Likewise. * ira-lives.cc (process_register_constraint_filters): New function. (process_bb_node_lives): Use it to record register filter information. * ira-color.cc (assign_hard_reg): Check register filters. (improve_allocation, fast_allocation): Likewise. --- gcc/ira-build.cc | 8 +++++++ gcc/ira-color.cc | 10 ++++++++ gcc/ira-int.h | 14 +++++++++++ gcc/ira-lives.cc | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+) diff --git a/gcc/ira-build.cc b/gcc/ira-build.cc index 93e46033170..c715a834f12 100644 --- a/gcc/ira-build.cc +++ b/gcc/ira-build.cc @@ -498,6 +498,7 @@ ira_create_allocno (int regno, bool cap_p, ALLOCNO_NREFS (a) = 0; ALLOCNO_FREQ (a) = 0; ALLOCNO_MIGHT_CONFLICT_WITH_PARENT_P (a) = false; + ALLOCNO_SET_REGISTER_FILTERS (a, 0); ALLOCNO_HARD_REGNO (a) = -1; ALLOCNO_CALL_FREQ (a) = 0; ALLOCNO_CALLS_CROSSED_NUM (a) = 0; @@ -902,6 +903,7 @@ create_cap_allocno (ira_allocno_t a) ALLOCNO_NREFS (cap) = ALLOCNO_NREFS (a); ALLOCNO_FREQ (cap) = ALLOCNO_FREQ (a); ALLOCNO_CALL_FREQ (cap) = ALLOCNO_CALL_FREQ (a); + ALLOCNO_SET_REGISTER_FILTERS (cap, ALLOCNO_REGISTER_FILTERS (a)); merge_hard_reg_conflicts (a, cap, false); @@ -2064,6 +2066,9 @@ propagate_allocno_info (void) ALLOCNO_BAD_SPILL_P (parent_a) = false; ALLOCNO_NREFS (parent_a) += ALLOCNO_NREFS (a); ALLOCNO_FREQ (parent_a) += ALLOCNO_FREQ (a); + ALLOCNO_SET_REGISTER_FILTERS (parent_a, + ALLOCNO_REGISTER_FILTERS (parent_a) + | ALLOCNO_REGISTER_FILTERS (a)); /* If A's allocation can differ from PARENT_A's, we can if necessary spill PARENT_A on entry to A's loop and restore it afterwards. @@ -2465,6 +2470,9 @@ propagate_some_info_from_allocno (ira_allocno_t a, ira_allocno_t from_a) ALLOCNO_CROSSED_CALLS_ABIS (a) |= ALLOCNO_CROSSED_CALLS_ABIS (from_a); ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a) |= ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (from_a); + ALLOCNO_SET_REGISTER_FILTERS (a, + ALLOCNO_REGISTER_FILTERS (from_a) + | ALLOCNO_REGISTER_FILTERS (a)); ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) += ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (from_a); diff --git a/gcc/ira-color.cc b/gcc/ira-color.cc index f2e8ea34152..214a4f16d3c 100644 --- a/gcc/ira-color.cc +++ b/gcc/ira-color.cc @@ -2163,6 +2163,9 @@ assign_hard_reg (ira_allocno_t a, bool retry_p) if (! check_hard_reg_p (a, hard_regno, conflicting_regs, profitable_hard_regs)) continue; + if (NUM_REGISTER_FILTERS + && !test_register_filters (ALLOCNO_REGISTER_FILTERS (a), hard_regno)) + continue; cost = costs[i]; full_cost = full_costs[i]; if (!HONOR_REG_ALLOC_ORDER) @@ -3205,6 +3208,9 @@ improve_allocation (void) if (! check_hard_reg_p (a, hregno, conflicting_regs, profitable_hard_regs)) continue; + if (NUM_REGISTER_FILTERS + && !test_register_filters (ALLOCNO_REGISTER_FILTERS (a), hregno)) + continue; ira_assert (ira_class_hard_reg_index[aclass][hregno] == j); k = allocno_costs == NULL ? 0 : j; costs[hregno] = (allocno_costs == NULL @@ -5275,6 +5281,10 @@ fast_allocation (void) || (TEST_HARD_REG_BIT (ira_prohibited_class_mode_regs[aclass][mode], hard_regno))) continue; + if (NUM_REGISTER_FILTERS + && !test_register_filters (ALLOCNO_REGISTER_FILTERS (a), + hard_regno)) + continue; if (costs == NULL) { best_hard_regno = hard_regno; diff --git a/gcc/ira-int.h b/gcc/ira-int.h index 0685e1f4e8d..1c3548df4ea 100644 --- a/gcc/ira-int.h +++ b/gcc/ira-int.h @@ -328,6 +328,13 @@ struct ira_allocno This is only ever true for non-cap allocnos. */ unsigned int might_conflict_with_parent_p : 1; +#ifndef NUM_REGISTER_FILTERS +#error "insn-config.h not included" +#elif NUM_REGISTER_FILTERS + /* The set of register filters applied to the allocno by operand + alternatives that accept class ACLASS. */ + unsigned int register_filters : NUM_REGISTER_FILTERS; +#endif /* Accumulated usage references of the allocno. Here and below, word 'accumulated' means info for given region and all nested subregions. In this case, 'accumulated' means sum of references @@ -432,6 +439,13 @@ struct ira_allocno #define ALLOCNO_FREQ(A) ((A)->freq) #define ALLOCNO_MIGHT_CONFLICT_WITH_PARENT_P(A) \ ((A)->might_conflict_with_parent_p) +#if NUM_REGISTER_FILTERS +#define ALLOCNO_REGISTER_FILTERS(A) (A)->register_filters +#define ALLOCNO_SET_REGISTER_FILTERS(A, X) ((A)->register_filters = (X)) +#else +#define ALLOCNO_REGISTER_FILTERS(A) 0 +#define ALLOCNO_SET_REGISTER_FILTERS(A, X) ((void) (A), gcc_assert ((X) == 0)) +#endif #define ALLOCNO_HARD_REGNO(A) ((A)->hard_regno) #define ALLOCNO_CALL_FREQ(A) ((A)->call_freq) #define ALLOCNO_CALLS_CROSSED_NUM(A) ((A)->calls_crossed_num) diff --git a/gcc/ira-lives.cc b/gcc/ira-lives.cc index 81af5c06460..63f2314409f 100644 --- a/gcc/ira-lives.cc +++ b/gcc/ira-lives.cc @@ -1066,6 +1066,66 @@ process_single_reg_class_operands (bool in_p, int freq) } } +/* Go through the operands of the extracted insn looking for operand + alternatives that apply a register filter. Record any such filters + in the operand's allocno. */ +static void +process_register_constraint_filters () +{ + for (int opno = 0; opno < recog_data.n_operands; ++opno) + { + rtx op = recog_data.operand[opno]; + if (SUBREG_P (op)) + op = SUBREG_REG (op); + if (REG_P (op) && !HARD_REGISTER_P (op)) + { + ira_allocno_t a = ira_curr_regno_allocno_map[REGNO (op)]; + for (int alt = 0; alt < recog_data.n_alternatives; alt++) + { + if (!TEST_BIT (preferred_alternatives, alt)) + continue; + + auto *op_alt = &recog_op_alt[alt * recog_data.n_operands]; + auto cl = alternative_class (op_alt, opno); + /* The two extremes are easy: + + - We should record the filter if CL matches the + allocno class. + + - We should ignore the filter if CL and the allocno class + are disjoint. We'll either pick a different alternative + or reload the operand. + + Things are trickier if the classes overlap. However: + + - If the allocno class includes registers that are not + in CL, some choices of hard register will need a reload + anyway. It isn't obvious that reloads due to filters + are worse than reloads due to regnos being outside CL. + + - Conversely, if the allocno class is a subset of CL, + any allocation will satisfy the class requirement. + We should try to make sure it satisfies the filter + requirement too. This is useful if, for example, + an allocno needs to be in "low" registers to satisfy + some uses, and its allocno class is therefore those + low registers, but the allocno is elsewhere allowed + to be in any even-numbered register. Picking an + even-numbered low register satisfies both types of use. */ + if (!ira_class_subset_p[ALLOCNO_CLASS (a)][cl]) + continue; + + auto filters = alternative_register_filters (op_alt, opno); + if (!filters) + continue; + + filters |= ALLOCNO_REGISTER_FILTERS (a); + ALLOCNO_SET_REGISTER_FILTERS (a, filters); + } + } + } +} + /* Look through the CALL_INSN_FUNCTION_USAGE of a call insn INSN, and see if we find a SET rtx that we can use to deduce that a register can be cheaply caller-saved. Return such a register, or NULL_RTX if none is found. */ @@ -1378,6 +1438,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node) } preferred_alternatives = ira_setup_alts (insn); + process_register_constraint_filters (); process_single_reg_class_operands (false, freq); if (call_p) From patchwork Sun Nov 12 14:52:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 1862855 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SSwYX01kyz1yQy for ; Mon, 13 Nov 2023 01:53:51 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7EA513858C78 for ; Sun, 12 Nov 2023 14:53:44 +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 85ADD3856975 for ; Sun, 12 Nov 2023 14:53:32 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 85ADD3856975 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 85ADD3856975 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=1699800813; cv=none; b=LumaGKaTti/BWiDdd55GExdIzkv+XXzDl3MnUs8J5D1rISh69Pq1EjsS0Su7+HMe3iWZjKygBiNf98yageN2FnysLyiPNfCCMR2Ksn20sUmvAFGdvhlGT3qmriDV9HG0Tsa9x44gGT3ugHS9Xb0MPvTanxPGX8GZqTwE56rcNJ4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699800813; c=relaxed/simple; bh=aHUFMzZBQL59w/1ZnMB5/68951o93y/qtZOfX1dHfi4=; h=From:To:Subject:Date:Message-Id:MIME-Version; b=HQeKDXCgXlN5YjmfNHZir15UFzKSwleqt4IDDOhqbAAHL6IVm4TsRb+rRfFdUozUbj/rylHqtFhcy5YqfMOLKMulsJcVdxmOjP5bYbtQt0+cbVckFTqNQHHuToxz5g+yIH0Z6K/v0KFYKvA8p/YM9720s6hiX1fFp627QnH0GoA= 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 4A09ADA7; Sun, 12 Nov 2023 06:54:17 -0800 (PST) Received: from e121540-lin.manchester.arm.com (e121540-lin.manchester.arm.com [10.32.110.72]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id A24133F7B4; Sun, 12 Nov 2023 06:53:31 -0800 (PST) From: Richard Sandiford To: jlaw@ventanamicro.com, vmakarov@redhat.com, gcc-patches@gcc.gnu.org Cc: Richard Sandiford Subject: [PATCH 5/5] Add an aligned_register_operand predicate Date: Sun, 12 Nov 2023 14:52:29 +0000 Message-Id: <20231112145229.2924713-6-richard.sandiford@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231112145229.2924713-1-richard.sandiford@arm.com> References: <20231112145229.2924713-1-richard.sandiford@arm.com> 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, KAM_SHORT, 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+incoming=patchwork.ozlabs.org@gcc.gnu.org This patch adds a target-independent aligned_register_operand predicate, for use with register constraints that use filters to impose an alignment. The definition deliberately jetisons some of the historical baggage in general_operand. gcc/ * common.md (aligned_register_operand): New predicate. --- gcc/common.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/gcc/common.md b/gcc/common.md index 51ecd79786b..91a72bd7731 100644 --- a/gcc/common.md +++ b/gcc/common.md @@ -17,6 +17,34 @@ ;; along with GCC; see the file COPYING3. If not see ;; . */ +;; This predicate is intended to be paired with register constraints that use +;; register filters to impose an alignment. Operands that are aligned via +;; TARGET_HARD_REGNO_MODE_OK should use normal register_operands instead. +(define_predicate "aligned_register_operand" + (match_code "reg,subreg") +{ + /* Require the offset in a non-paradoxical subreg to be naturally aligned. + For example, if we have a subreg of something that is double the size of + this operand, the offset must select the first or second half of it. */ + if (SUBREG_P (op) + && multiple_p (SUBREG_BYTE (op), GET_MODE_SIZE (GET_MODE (op)))) + op = SUBREG_REG (op); + if (!REG_P (op)) + return false; + + if (HARD_REGISTER_P (op)) + { + if (!in_hard_reg_set_p (operand_reg_set, GET_MODE (op), REGNO (op))) + return false; + + /* Reject hard registers that would need reloading, so that the reload + is visible to IRA and to pre-RA optimizers. */ + if (REGNO (op) % REG_NREGS (op) != 0) + return false; + } + return true; +}) + (define_register_constraint "r" "GENERAL_REGS" "Matches any general register.")