From patchwork Thu Sep 18 10:25:10 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 390742 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41E451401F1 for ; Thu, 18 Sep 2014 20:25:25 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:references:date:in-reply-to:message-id:mime-version :content-type:content-transfer-encoding; q=dns; s=default; b=Mty 7AVQRS9W++l8TF5HtmXEEEe1pYGARtTT8utX9R+arvosDo/bzI+RH6bucxojLfIm UIGfRiW4Y40a4n+5a2tz3Bl+1OW8bAxuyG2apps5mQoZwQcW3D701ZhP5ZFiM42d 7Zck1TYQ3HZ06Pr5mb4yjbCj1Vyxuz6RRBj/WLlM= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:references:date:in-reply-to:message-id:mime-version :content-type:content-transfer-encoding; s=default; bh=/GJPrnK7M NFMJ1Z+xwNoZpW8YSk=; b=SYUDUJQo33o843tzK/UnLx5xTHGDV5vCBOVOQSi/7 ugI+/sy1yRWkWbiXiiZHVu5MN58J4cMa9e0D+2oeu3RNhUyCqr+uQqJbqkTt2dFU 8YgktIwlepLvKtSNcLaG46RnVSnHZyXC5tvvJ8qYulaAMJpz3zlGGDDraYAwP7JN Mk= 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-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@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 11:25:10 +0100 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 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 =================================================================== --- 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 +#include "hash-table.h" + /* Define the type of a set of hard registers. */ /* 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 extern char global_regs[FIRST_PSEUDO_REGISTER]; +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; @@ -688,6 +694,10 @@ struct target_hard_regs { /* 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; }; extern struct target_hard_regs default_target_hard_regs; Index: gcc/target-globals.c =================================================================== --- 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 != &default_target_globals) { + hard_regs->finalize (); XDELETE (flag_state); XDELETE (regs); XDELETE (recog); Index: gcc/rtl.h =================================================================== --- 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 += COSTS_N_INSNS (n); } +/* Describes the shape of a subreg: + + inner_mode == the mode of the SUBREG_REG + offset == the SUBREG_BYTE + outer_mode == the mode of the SUBREG itself. */ +struct subreg_shape { + subreg_shape (enum machine_mode, unsigned int, enum machine_mode); + bool operator == (const subreg_shape &) const; + bool operator != (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 == (const subreg_shape &other) const +{ + return (inner_mode == other.inner_mode + && offset == other.offset + && outer_mode == other.outer_mode); +} + +inline bool +subreg_shape::operator != (const subreg_shape &other) const +{ + return !operator == (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 <= 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 /* In emit-rtl.c */ extern rtx set_for_reg_notes (rtx); Index: gcc/reginfo.c =================================================================== --- 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 int max_regno; +/* 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 *); +}; 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, } +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 == *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 + = new hash_table (30); + simplifiable_subreg **slot + = (this_target_hard_regs->x_simplifiable_subregs + ->find_slot_with_hash (&shape, shape.unique_id (), INSERT)); + + if (!*slot) + { + simplifiable_subreg *info = new simplifiable_subreg (shape); + for (unsigned int i = 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) >= 0) + SET_HARD_REG_BIT (info->simplifiable_regs, i); + *slot = info; + } + return (*slot)->simplifiable_regs; +} /* Passes for keeping and updating info about modes of registers inside subregisters. */ -#ifdef CANNOT_CHANGE_MODE_CLASS - -static bitmap invalid_mode_changes; +static HARD_REG_SET **valid_mode_changes; +static obstack valid_mode_changes_obstack; 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; if (!REG_P (SUBREG_REG (subreg))) return; regno = REGNO (SUBREG_REG (subreg)); - mode = GET_MODE (subreg); - if (regno < FIRST_PSEUDO_REGISTER) return; - 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 = 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] + = XOBNEW (&valid_mode_changes_obstack, HARD_REG_SET); + COPY_HARD_REG_SET (*valid_mode_changes[regno], + simplifiable_subregs (shape_of_subreg (subreg))); } } /* 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 = GET_CODE (x); const char * const fmt = GET_RTX_FORMAT (code); int i; if (code == SUBREG) - record_subregs_of_mode (x, subregs_of_mode); + record_subregs_of_mode (x); /* Time for some deep diving. */ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') - find_subregs_of_mode (XEXP (x, i), subregs_of_mode); + find_subregs_of_mode (XEXP (x, i)); else if (fmt[i] == 'E') { int j; for (j = XVECLEN (x, i) - 1; j >= 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; - gcc_assert (invalid_mode_changes == NULL); - invalid_mode_changes = BITMAP_ALLOC (NULL); - bitmap_obstack_initialize (&srom_obstack); - subregs_of_mode = BITMAP_ALLOC (&srom_obstack); + gcc_obstack_init (&valid_mode_changes_obstack); + valid_mode_changes = XCNEWVEC (HARD_REG_SET *, max_reg_num ()); 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)); } /* 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])); } 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 because + 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 =================================================================== --- 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 = 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 = 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) {