From owner-svn-src-all@FreeBSD.ORG Sat Nov 16 01:29:28 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 48336AD1; Sat, 16 Nov 2013 01:29:28 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 36CE6225F; Sat, 16 Nov 2013 01:29:28 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id rAG1TSg3070685; Sat, 16 Nov 2013 01:29:28 GMT (envelope-from pfg@svn.freebsd.org) Received: (from pfg@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id rAG1TRjG070681; Sat, 16 Nov 2013 01:29:27 GMT (envelope-from pfg@svn.freebsd.org) Message-Id: <201311160129.rAG1TRjG070681@svn.freebsd.org> From: "Pedro F. Giffuni" Date: Sat, 16 Nov 2013 01:29:27 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r258207 - head/contrib/gcc X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 16 Nov 2013 01:29:28 -0000 Author: pfg Date: Sat Nov 16 01:29:27 2013 New Revision: 258207 URL: http://svnweb.freebsd.org/changeset/base/258207 Log: gcc: Fix postreload-gcse treatment of call-clobbered registers. Reference: http://gcc.gnu.org/ml/gcc-patches/2007-05/msg01636.html Obtained from: gcc 4.3 (rev. 125037; GPLv2) MFC after: 3 weeks Modified: head/contrib/gcc/ChangeLog.gcc43 head/contrib/gcc/postreload-gcse.c head/contrib/gcc/regs.h head/contrib/gcc/rtlanal.c Modified: head/contrib/gcc/ChangeLog.gcc43 ============================================================================== --- head/contrib/gcc/ChangeLog.gcc43 Sat Nov 16 01:16:24 2013 (r258206) +++ head/contrib/gcc/ChangeLog.gcc43 Sat Nov 16 01:29:27 2013 (r258207) @@ -4,6 +4,21 @@ * doc/extend.texi: Document the 0b-prefixed binary integer constant extension. +2007-05-24 Richard Sandiford (r125037) + + * postreload-gcse.c (reg_changed_after_insn_p): New function. + (oprs_unchanged_p): Use it to check all registers in a REG. + (record_opr_changes): Look for clobbers in CALL_INSN_FUNCTION_USAGE. + (reg_set_between_after_reload_p): Delete. + (reg_used_between_after_reload_p): Likewise. + (reg_set_or_used_since_bb_start): Likewise. + (eliminate_partially_redundant_load): Use reg_changed_after_insn_p + and reg_used_between_p instead of reg_set_or_used_since_bb_start. + Use reg_set_between_p instead of reg_set_between_after_reload_p. + * rtlanal.c (reg_set_p): Check whether REG overlaps + regs_invalidated_by_call, rather than just checking the + membership of REGNO (REG). + 2007-05-03 Ian Lance Taylor (r124381) * config/rs6000/rs6000.c (rs6000_override_options): Don't set Modified: head/contrib/gcc/postreload-gcse.c ============================================================================== --- head/contrib/gcc/postreload-gcse.c Sat Nov 16 01:16:24 2013 (r258206) +++ head/contrib/gcc/postreload-gcse.c Sat Nov 16 01:29:27 2013 (r258207) @@ -197,8 +197,6 @@ static void dump_hash_table (FILE *); static bool reg_killed_on_edge (rtx, edge); static bool reg_used_on_edge (rtx, edge); -static rtx reg_set_between_after_reload_p (rtx, rtx, rtx); -static rtx reg_used_between_after_reload_p (rtx, rtx, rtx); static rtx get_avail_load_store_reg (rtx); static bool bb_has_well_behaved_predecessors (basic_block); @@ -470,6 +468,22 @@ dump_hash_table (FILE *file) fprintf (file, "\n"); } +/* Return true if register X is recorded as being set by an instruction + whose CUID is greater than the one given. */ + +static bool +reg_changed_after_insn_p (rtx x, int cuid) +{ + unsigned int regno, end_regno; + + regno = REGNO (x); + end_regno = END_HARD_REGNO (x); + do + if (reg_avail_info[regno] > cuid) + return true; + while (++regno < end_regno); + return false; +} /* Return nonzero if the operands of expression X are unchanged 1) from the start of INSN's basic block up to but not including INSN @@ -493,14 +507,9 @@ oprs_unchanged_p (rtx x, rtx insn, bool /* We are called after register allocation. */ gcc_assert (REGNO (x) < FIRST_PSEUDO_REGISTER); if (after_insn) - /* If the last CUID setting the insn is less than the CUID of - INSN, then reg X is not changed in or after INSN. */ - return reg_avail_info[REGNO (x)] < INSN_CUID (insn); + return !reg_changed_after_insn_p (x, INSN_CUID (insn) - 1); else - /* Reg X is not set before INSN in the current basic block if - we have not yet recorded the CUID of an insn that touches - the reg. */ - return reg_avail_info[REGNO (x)] == 0; + return !reg_changed_after_insn_p (x, 0); case MEM: if (load_killed_in_block_p (INSN_CUID (insn), x, after_insn)) @@ -717,12 +726,28 @@ record_opr_changes (rtx insn) /* Finally, if this is a call, record all call clobbers. */ if (CALL_P (insn)) { - unsigned int regno; + unsigned int regno, end_regno; + rtx link, x; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno)) record_last_reg_set_info (insn, regno); + for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1)) + if (GET_CODE (XEXP (link, 0)) == CLOBBER) + { + x = XEXP (XEXP (link, 0), 0); + if (REG_P (x)) + { + gcc_assert (HARD_REGISTER_P (x)); + regno = REGNO (x); + end_regno = END_HARD_REGNO (x); + do + record_last_reg_set_info (insn, regno); + while (++regno < end_regno); + } + } + if (! CONST_OR_PURE_CALL_P (insn)) record_last_mem_set_info (insn); } @@ -856,96 +881,6 @@ reg_used_on_edge (rtx reg, edge e) return false; } - -/* Return the insn that sets register REG or clobbers it in between - FROM_INSN and TO_INSN (exclusive of those two). - Just like reg_set_between but for hard registers and not pseudos. */ - -static rtx -reg_set_between_after_reload_p (rtx reg, rtx from_insn, rtx to_insn) -{ - rtx insn; - - /* We are called after register allocation. */ - gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER); - - if (from_insn == to_insn) - return NULL_RTX; - - for (insn = NEXT_INSN (from_insn); - insn != to_insn; - insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - { - if (set_of (reg, insn) != NULL_RTX) - return insn; - if ((CALL_P (insn) - && call_used_regs[REGNO (reg)]) - || find_reg_fusage (insn, CLOBBER, reg)) - return insn; - - if (FIND_REG_INC_NOTE (insn, reg)) - return insn; - } - - return NULL_RTX; -} - -/* Return the insn that uses register REG in between FROM_INSN and TO_INSN - (exclusive of those two). Similar to reg_used_between but for hard - registers and not pseudos. */ - -static rtx -reg_used_between_after_reload_p (rtx reg, rtx from_insn, rtx to_insn) -{ - rtx insn; - - /* We are called after register allocation. */ - gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER); - - if (from_insn == to_insn) - return NULL_RTX; - - for (insn = NEXT_INSN (from_insn); - insn != to_insn; - insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - { - if (reg_overlap_mentioned_p (reg, PATTERN (insn)) - || (CALL_P (insn) - && call_used_regs[REGNO (reg)]) - || find_reg_fusage (insn, USE, reg) - || find_reg_fusage (insn, CLOBBER, reg)) - return insn; - - if (FIND_REG_INC_NOTE (insn, reg)) - return insn; - } - - return NULL_RTX; -} - -/* Return true if REG is used, set, or killed between the beginning of - basic block BB and UP_TO_INSN. Caches the result in reg_avail_info. */ - -static bool -reg_set_or_used_since_bb_start (rtx reg, basic_block bb, rtx up_to_insn) -{ - rtx insn, start = PREV_INSN (BB_HEAD (bb)); - - if (reg_avail_info[REGNO (reg)] != 0) - return true; - - insn = reg_used_between_after_reload_p (reg, start, up_to_insn); - if (! insn) - insn = reg_set_between_after_reload_p (reg, start, up_to_insn); - - if (insn) - reg_avail_info[REGNO (reg)] = INSN_CUID (insn); - - return insn != NULL_RTX; -} - /* Return the loaded/stored register of a load/store instruction. */ static rtx @@ -1037,7 +972,8 @@ eliminate_partially_redundant_load (basi /* Check that the loaded register is not used, set, or killed from the beginning of the block. */ - if (reg_set_or_used_since_bb_start (dest, bb, insn)) + if (reg_changed_after_insn_p (dest, 0) + || reg_used_between_p (dest, PREV_INSN (BB_HEAD (bb)), insn)) return; /* Check potential for replacing load with copy for predecessors. */ @@ -1068,8 +1004,7 @@ eliminate_partially_redundant_load (basi avail_insn = NULL; continue; } - if (! reg_set_between_after_reload_p (avail_reg, avail_insn, - next_pred_bb_end)) + if (!reg_set_between_p (avail_reg, avail_insn, next_pred_bb_end)) /* AVAIL_INSN remains non-null. */ break; else Modified: head/contrib/gcc/regs.h ============================================================================== --- head/contrib/gcc/regs.h Sat Nov 16 01:16:24 2013 (r258206) +++ head/contrib/gcc/regs.h Sat Nov 16 01:29:27 2013 (r258207) @@ -239,5 +239,41 @@ extern void allocate_reg_info (size_t, i /* Specify number of hard registers given machine mode occupy. */ extern unsigned char hard_regno_nregs[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE]; +/* Return an exclusive upper bound on the registers occupied by hard + register (reg:MODE REGNO). */ + +static inline unsigned int +end_hard_regno (enum machine_mode mode, unsigned int regno) +{ + return regno + hard_regno_nregs[regno][(int) mode]; +} + +/* Likewise for hard register X. */ + +#define END_HARD_REGNO(X) end_hard_regno (GET_MODE (X), REGNO (X)) + +/* Likewise for hard or pseudo register X. */ + +#define END_REGNO(X) (HARD_REGISTER_P (X) ? END_HARD_REGNO (X) : REGNO (X) + 1) + + +/* Return true if (reg:MODE REGNO) includes an element of REGS. */ + +static inline bool +overlaps_hard_reg_set_p (const HARD_REG_SET regs, enum machine_mode mode, + unsigned int regno) +{ + unsigned int end_regno; + + if (TEST_HARD_REG_BIT (regs, regno)) + return true; + + end_regno = end_hard_regno (mode, regno); + while (++regno < end_regno) + if (TEST_HARD_REG_BIT (regs, regno)) + return true; + + return false; +} #endif /* GCC_REGS_H */ Modified: head/contrib/gcc/rtlanal.c ============================================================================== --- head/contrib/gcc/rtlanal.c Sat Nov 16 01:16:24 2013 (r258206) +++ head/contrib/gcc/rtlanal.c Sat Nov 16 01:29:27 2013 (r258207) @@ -748,8 +748,8 @@ reg_set_p (rtx reg, rtx insn) || (CALL_P (insn) && ((REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER - && TEST_HARD_REG_BIT (regs_invalidated_by_call, - REGNO (reg))) + && overlaps_hard_reg_set_p (regs_invalidated_by_call, + GET_MODE (reg), REGNO (reg))) || MEM_P (reg) || find_reg_fusage (insn, CLOBBER, reg))))) return 1;