From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29680 invoked by alias); 18 Sep 2014 10:25:18 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 29664 invoked by uid 89); 18 Sep 2014 10:25:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.8 required=5.0 tests=AWL,BAYES_00,SPF_PASS autolearn=ham version=3.3.2 X-HELO: service87.mimecast.com Received: from service87.mimecast.com (HELO service87.mimecast.com) (91.220.42.44) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 18 Sep 2014 10:25:14 +0000 Received: from cam-owa1.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.21]) by service87.mimecast.com; Thu, 18 Sep 2014 11:25:11 +0100 Received: from localhost ([10.1.255.212]) by cam-owa1.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Thu, 18 Sep 2014 11:25:11 +0100 From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, richard.sandiford@arm.com Subject: [PATCH 4/5] Generalise invalid_mode_change_p References: <87ppetnsxd.fsf@e105548-lin.cambridge.arm.com> Date: Thu, 18 Sep 2014 10:25:00 -0000 In-Reply-To: <87ppetnsxd.fsf@e105548-lin.cambridge.arm.com> (Richard Sandiford's message of "Thu, 18 Sep 2014 11:07:10 +0100") Message-ID: <878ulhns3d.fsf@e105548-lin.cambridge.arm.com> User-Agent: Gnus/5.130012 (Ma Gnus v0.12) Emacs/24.3 (gnu/linux) MIME-Version: 1.0 X-MC-Unique: 114091811251103201 Content-Type: text/plain; charset=WINDOWS-1252 Content-Transfer-Encoding: quoted-printable X-SW-Source: 2014-09/txt/msg01449.txt.bz2 This is the main patch for the bug. We should treat a register as invalid for a mode change if simplify_subreg_regno cannot provide a new register number for the result. We should treat a class as invalid for a mode change if all registers in the class are invalid. This is an extension of the old CANNOT_CHANGE_MODE_CLASS-based check (simplify_subreg_regno checks C_C_C_M). I forgot to say that the patch is a prerequisite to removing aarch64's C_C_C_M. There are other prerequisites too, but removing C_C_C_M without this patch caused regressions in the existing testsuite, which is why no new tests are needed. gcc/ * hard-reg-set.h: Include hash-table.h. (target_hard_regs): Add a finalize method and a x_simplifiable_subregs field. * target-globals.c (target_globals::~target_globals): Handle hard_regs->finalize. * rtl.h (subreg_shape): New structure. (shape_of_subreg): New function. (simplifiable_subregs): Declare. * reginfo.c (simplifiable_subreg): New structure. (simplifiable_subregs_hasher): Likewise. (simplifiable_subregs): New function. (invalid_mode_changes): Delete. (alid_mode_changes, valid_mode_changes_obstack): New variables. (record_subregs_of_mode): Remove subregs_of_mode parameter. Record valid mode changes in valid_mode_changes. (find_subregs_of_mode): Remove subregs_of_mode parameter. Update calls to record_subregs_of_mode. (init_subregs_of_mode): Remove invalid_mode_changes and bitmap handling. Initialize new variables. Update call to find_subregs_of_mode. (invalid_mode_change_p): Check new variables instead of invalid_mode_changes. (finish_subregs_of_mode): Finalize new variables instead of invalid_mode_changes. (target_hard_regs::finalize): New function. * ira-costs.c (print_allocno_costs): Call invalid_mode_change_p even when CLASS_CANNOT_CHANGE_MODE is undefined. Index: gcc/hard-reg-set.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- gcc/hard-reg-set.h 2014-09-15 11:55:40.459855161 +0100 +++ gcc/hard-reg-set.h 2014-09-15 11:55:40.455855210 +0100 @@ -20,6 +20,8 @@ Software Foundation; either version 3, o #ifndef GCC_HARD_REG_SET_H #define GCC_HARD_REG_SET_H =20 +#include "hash-table.h" + /* Define the type of a set of hard registers. */ =20 /* HARD_REG_ELT_TYPE is a typedef of the unsigned integral type which @@ -613,7 +615,11 @@ #define EXECUTE_IF_SET_IN_HARD_REG_SET(S =20 extern char global_regs[FIRST_PSEUDO_REGISTER]; =20 +struct simplifiable_subregs_hasher; + struct target_hard_regs { + void finalize (); + /* The set of registers that actually exist on the current target. */ HARD_REG_SET x_accessible_reg_set; =20 @@ -688,6 +694,10 @@ struct target_hard_regs { =20 /* Vector indexed by hardware reg giving its name. */ const char *x_reg_names[FIRST_PSEUDO_REGISTER]; + + /* Records which registers can form a particular subreg, with the subreg + being identified by its outer mode, inner mode and offset. */ + hash_table *x_simplifiable_subregs; }; =20 extern struct target_hard_regs default_target_hard_regs; Index: gcc/target-globals.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- gcc/target-globals.c 2014-09-15 11:55:40.459855161 +0100 +++ gcc/target-globals.c 2014-09-15 11:55:40.459855161 +0100 @@ -125,6 +125,7 @@ target_globals::~target_globals () /* default_target_globals points to static data so shouldn't be freed. = */ if (this !=3D &default_target_globals) { + hard_regs->finalize (); XDELETE (flag_state); XDELETE (regs); XDELETE (recog); Index: gcc/rtl.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- gcc/rtl.h 2014-09-15 11:55:40.459855161 +0100 +++ gcc/rtl.h 2014-09-15 12:26:21.249077760 +0100 @@ -1822,6 +1822,64 @@ costs_add_n_insns (struct full_rtx_costs c->size +=3D COSTS_N_INSNS (n); } =20 +/* Describes the shape of a subreg: + + inner_mode =3D=3D the mode of the SUBREG_REG + offset =3D=3D the SUBREG_BYTE + outer_mode =3D=3D the mode of the SUBREG itself. */ +struct subreg_shape { + subreg_shape (enum machine_mode, unsigned int, enum machine_mode); + bool operator =3D=3D (const subreg_shape &) const; + bool operator !=3D (const subreg_shape &) const; + unsigned int unique_id () const; + + enum machine_mode inner_mode; + unsigned int offset; + enum machine_mode outer_mode; +}; + +inline +subreg_shape::subreg_shape (enum machine_mode inner_mode_in, + unsigned int offset_in, + enum machine_mode outer_mode_in) + : inner_mode (inner_mode_in), offset (offset_in), outer_mode (outer_mode= _in) +{} + +inline bool +subreg_shape::operator =3D=3D (const subreg_shape &other) const +{ + return (inner_mode =3D=3D other.inner_mode + && offset =3D=3D other.offset + && outer_mode =3D=3D other.outer_mode); +} + +inline bool +subreg_shape::operator !=3D (const subreg_shape &other) const +{ + return !operator =3D=3D (other); +} + +/* Return an integer that uniquely identifies this shape. Structures + like rtx_def assume that a mode can fit in an 8-bit bitfield and no + current mode is anywhere near being 65536 bytes in size, so the + id comfortably fits in an int. */ + +inline unsigned int +subreg_shape::unique_id () const +{ + STATIC_ASSERT (MAX_MACHINE_MODE <=3D 256); + return (int) inner_mode + ((int) outer_mode << 8) + (offset << 16); +} + +/* Return the shape of a SUBREG rtx. */ + +static inline subreg_shape +shape_of_subreg (const_rtx x) +{ + return subreg_shape (GET_MODE (SUBREG_REG (x)), + SUBREG_BYTE (x), GET_MODE (x)); +} + /* Information about an address. This structure is supposed to be able to represent all supported target addresses. Please extend it if it is not yet general enough. */ @@ -2718,6 +2776,9 @@ extern bool val_signbit_known_clear_p (e /* In reginfo.c */ extern enum machine_mode choose_hard_reg_mode (unsigned int, unsigned int, bool); +#ifdef HARD_CONST +extern const HARD_REG_SET &simplifiable_subregs (const subreg_shape &); +#endif =20 /* In emit-rtl.c */ extern rtx set_for_reg_notes (rtx); Index: gcc/reginfo.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- gcc/reginfo.c 2014-09-15 11:55:40.459855161 +0100 +++ gcc/reginfo.c 2014-09-18 11:22:12.520550755 +0100 @@ -54,6 +54,24 @@ Software Foundation; either version 3, o =20 int max_regno; =20 +/* Used to cache the results of simplifiable_subregs. SHAPE is the input + parameter and SIMPLIFIABLE_REGS is the result. */ +struct simplifiable_subreg +{ + simplifiable_subreg (const subreg_shape &); + + subreg_shape shape; + HARD_REG_SET simplifiable_regs; +}; + +struct simplifiable_subregs_hasher : typed_noop_remove +{ + typedef simplifiable_subreg value_type; + typedef subreg_shape compare_type; + + static inline hashval_t hash (const value_type *); + static inline bool equal (const value_type *, const compare_type *); +}; =0C struct target_hard_regs default_target_hard_regs; struct target_regs default_target_regs; @@ -1193,64 +1211,102 @@ reg_classes_intersect_p (reg_class_t c1, } =20 =0C +inline hashval_t +simplifiable_subregs_hasher::hash (const value_type *value) +{ + return value->shape.unique_id (); +} + +inline bool +simplifiable_subregs_hasher::equal (const value_type *value, + const compare_type *compare) +{ + return value->shape =3D=3D *compare; +} + +inline simplifiable_subreg::simplifiable_subreg (const subreg_shape &shape= _in) + : shape (shape_in) +{ + CLEAR_HARD_REG_SET (simplifiable_regs); +} + +/* Return the set of hard registers that are able to form the subreg + described by SHAPE. */ + +const HARD_REG_SET & +simplifiable_subregs (const subreg_shape &shape) +{ + if (!this_target_hard_regs->x_simplifiable_subregs) + this_target_hard_regs->x_simplifiable_subregs + =3D new hash_table (30); + simplifiable_subreg **slot + =3D (this_target_hard_regs->x_simplifiable_subregs + ->find_slot_with_hash (&shape, shape.unique_id (), INSERT)); + + if (!*slot) + { + simplifiable_subreg *info =3D new simplifiable_subreg (shape); + for (unsigned int i =3D 0; i < FIRST_PSEUDO_REGISTER; ++i) + if (HARD_REGNO_MODE_OK (i, shape.inner_mode) + && simplify_subreg_regno (i, shape.inner_mode, shape.offset, + shape.outer_mode) >=3D 0) + SET_HARD_REG_BIT (info->simplifiable_regs, i); + *slot =3D info; + } + return (*slot)->simplifiable_regs; +} =20 /* Passes for keeping and updating info about modes of registers inside subregisters. */ =20 -#ifdef CANNOT_CHANGE_MODE_CLASS - -static bitmap invalid_mode_changes; +static HARD_REG_SET **valid_mode_changes; +static obstack valid_mode_changes_obstack; =20 static void -record_subregs_of_mode (rtx subreg, bitmap subregs_of_mode) +record_subregs_of_mode (rtx subreg) { - enum machine_mode mode; unsigned int regno; =20 if (!REG_P (SUBREG_REG (subreg))) return; =20 regno =3D REGNO (SUBREG_REG (subreg)); - mode =3D GET_MODE (subreg); - if (regno < FIRST_PSEUDO_REGISTER) return; =20 - if (bitmap_set_bit (subregs_of_mode, - regno * NUM_MACHINE_MODES + (unsigned int) mode)) + if (valid_mode_changes[regno]) + AND_HARD_REG_SET (*valid_mode_changes[regno], + simplifiable_subregs (shape_of_subreg (subreg))); + else { - unsigned int rclass; - for (rclass =3D 0; rclass < N_REG_CLASSES; rclass++) - if (!bitmap_bit_p (invalid_mode_changes, - regno * N_REG_CLASSES + rclass) - && CANNOT_CHANGE_MODE_CLASS (PSEUDO_REGNO_MODE (regno), - mode, (enum reg_class) rclass)) - bitmap_set_bit (invalid_mode_changes, - regno * N_REG_CLASSES + rclass); + valid_mode_changes[regno] + =3D XOBNEW (&valid_mode_changes_obstack, HARD_REG_SET); + COPY_HARD_REG_SET (*valid_mode_changes[regno], + simplifiable_subregs (shape_of_subreg (subreg))); } } =20 /* Call record_subregs_of_mode for all the subregs in X. */ static void -find_subregs_of_mode (rtx x, bitmap subregs_of_mode) +find_subregs_of_mode (rtx x) { enum rtx_code code =3D GET_CODE (x); const char * const fmt =3D GET_RTX_FORMAT (code); int i; =20 if (code =3D=3D SUBREG) - record_subregs_of_mode (x, subregs_of_mode); + record_subregs_of_mode (x); =20 /* Time for some deep diving. */ for (i =3D GET_RTX_LENGTH (code) - 1; i >=3D 0; i--) { if (fmt[i] =3D=3D 'e') - find_subregs_of_mode (XEXP (x, i), subregs_of_mode); + find_subregs_of_mode (XEXP (x, i)); else if (fmt[i] =3D=3D 'E') { int j; for (j =3D XVECLEN (x, i) - 1; j >=3D 0; j--) - find_subregs_of_mode (XVECEXP (x, i, j), subregs_of_mode); + find_subregs_of_mode (XVECEXP (x, i, j)); } } } @@ -1260,46 +1316,38 @@ init_subregs_of_mode (void) { basic_block bb; rtx_insn *insn; - bitmap_obstack srom_obstack; - bitmap subregs_of_mode; =20 - gcc_assert (invalid_mode_changes =3D=3D NULL); - invalid_mode_changes =3D BITMAP_ALLOC (NULL); - bitmap_obstack_initialize (&srom_obstack); - subregs_of_mode =3D BITMAP_ALLOC (&srom_obstack); + gcc_obstack_init (&valid_mode_changes_obstack); + valid_mode_changes =3D XCNEWVEC (HARD_REG_SET *, max_reg_num ()); =20 FOR_EACH_BB_FN (bb, cfun) FOR_BB_INSNS (bb, insn) if (NONDEBUG_INSN_P (insn)) - find_subregs_of_mode (PATTERN (insn), subregs_of_mode); - - BITMAP_FREE (subregs_of_mode); - bitmap_obstack_release (&srom_obstack); + find_subregs_of_mode (PATTERN (insn)); } =20 /* Return 1 if REGNO has had an invalid mode change in CLASS from FROM mode. */ bool -invalid_mode_change_p (unsigned int regno, - enum reg_class rclass) +invalid_mode_change_p (unsigned int regno, enum reg_class rclass) { - return bitmap_bit_p (invalid_mode_changes, - regno * N_REG_CLASSES + (unsigned) rclass); + return (valid_mode_changes[regno] + && !hard_reg_set_intersect_p (reg_class_contents[rclass], + *valid_mode_changes[regno])); } =20 void finish_subregs_of_mode (void) { - BITMAP_FREE (invalid_mode_changes); -} -#else -void -init_subregs_of_mode (void) -{ + XDELETEVEC (valid_mode_changes); + obstack_finish (&valid_mode_changes_obstack); } + +/* Free all data attached to the structure. This isn't a destructor becau= se + we don't want to run on exit. */ + void -finish_subregs_of_mode (void) +target_hard_regs::finalize () { + delete x_simplifiable_subregs; } - -#endif /* CANNOT_CHANGE_MODE_CLASS */ Index: gcc/ira-costs.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- gcc/ira-costs.c 2014-09-15 11:55:40.459855161 +0100 +++ gcc/ira-costs.c 2014-09-15 11:55:40.455855210 +0100 @@ -1438,10 +1438,7 @@ print_allocno_costs (FILE *f) { rclass =3D cost_classes[k]; if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)] -#ifdef CANNOT_CHANGE_MODE_CLASS - && ! invalid_mode_change_p (regno, (enum reg_class) rclass) -#endif - ) + && ! invalid_mode_change_p (regno, (enum reg_class) rclass)) { fprintf (f, " %s:%d", reg_class_names[rclass], COSTS (costs, i)->cost[k]); @@ -1480,10 +1477,7 @@ print_pseudo_costs (FILE *f) { rclass =3D cost_classes[k]; if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)] -#ifdef CANNOT_CHANGE_MODE_CLASS - && ! invalid_mode_change_p (regno, (enum reg_class) rclass) -#endif - ) + && ! invalid_mode_change_p (regno, (enum reg_class) rclass)) fprintf (f, " %s:%d", reg_class_names[rclass], COSTS (costs, regno)->cost[k]); } @@ -1725,10 +1719,7 @@ find_costs_and_classes (FILE *dump_file) /* Ignore classes that are too small or invalid for this operand. */ if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)] -#ifdef CANNOT_CHANGE_MODE_CLASS - || invalid_mode_change_p (i, (enum reg_class) rclass) -#endif - ) + || invalid_mode_change_p (i, (enum reg_class) rclass)) continue; if (i_costs[k] < best_cost) { @@ -1822,10 +1813,7 @@ find_costs_and_classes (FILE *dump_file) /* Ignore classes that are too small or invalid for this operand. */ if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)] -#ifdef CANNOT_CHANGE_MODE_CLASS - || invalid_mode_change_p (i, (enum reg_class) rclass) -#endif - ) + || invalid_mode_change_p (i, (enum reg_class) rclass)) ; else if (total_a_costs[k] < best_cost) {