[backport gcc-4.9/trunk r199353, needs followup fix to unbreak m68k ] List-Archive: Date: Wed, 15 May 2013 11:00:02 -0400 From: Joern Rennecke Subject: RFA: fix rtl-optimization/56833 The problem was that we had some optimzations added to the reload_cse_move2add pass that would attempt transformations with multi-hard-register registers, without keeping track of the validity of the values in all hard registers involved. The attached patch fixes this by updating reg_set_luid for all hard regs involved in a set, and requiring identical reg_set_luid values for all hard regs involved when using a value. bootstrapped/regtested on i686-pc-linux-gnu gcc/ 2013-05-27 Joern Rennecke PR rtl-optimization/56833 * postreload.c (move2add_record_mode): New function. (move2add_record_sym_value, move2add_valid_value_p): Likewise. (move2add_use_add2_insn): Use move2add_record_sym_value. (move2add_use_add3_insn): Likewise. (reload_cse_move2add): Use move2add_valid_value_p and move2add_record_mode. Invalidate call-clobbered and REG_INC affected regs by setting reg_mode to VOIDmode. (move2add_note_store): Don't pretend the inside of a SUBREG is the actual destination. Invalidate single/leading registers by setting reg_mode to VOIDmode. Use move2add_record_sym_value, move2add_valid_value_p and move2add_record_mode. --- gcc-4.8.1/gcc/postreload.c.~1~ 2013-01-10 21:38:27.000000000 +0100 +++ gcc-4.8.1/gcc/postreload.c 2013-06-01 11:14:29.428978150 +0200 @@ -1639,14 +1639,22 @@ reload_combine_note_use (rtx *xp, rtx in later disable any optimization that would cross it. reg_offset[n] / reg_base_reg[n] / reg_symbol_ref[n] / reg_mode[n] are only valid if reg_set_luid[n] is greater than - move2add_last_label_luid. */ + move2add_last_label_luid. + For a set that established a new (potential) base register with + non-constant value, we use move2add_luid from the place where the + setting insn is encountered; registers based off that base then + get the same reg_set_luid. Constants all get + move2add_last_label_luid + 1 as their reg_set_luid. */ static int reg_set_luid[FIRST_PSEUDO_REGISTER]; /* If reg_base_reg[n] is negative, register n has been set to reg_offset[n] or reg_symbol_ref[n] + reg_offset[n] in mode reg_mode[n]. If reg_base_reg[n] is non-negative, register n has been set to the sum of reg_offset[n] and the value of register reg_base_reg[n] - before reg_set_luid[n], calculated in mode reg_mode[n] . */ + before reg_set_luid[n], calculated in mode reg_mode[n] . + For multi-hard-register registers, all but the first one are + recorded as BLKmode in reg_mode. Setting reg_mode to VOIDmode + marks it as invalid. */ static HOST_WIDE_INT reg_offset[FIRST_PSEUDO_REGISTER]; static int reg_base_reg[FIRST_PSEUDO_REGISTER]; static rtx reg_symbol_ref[FIRST_PSEUDO_REGISTER]; @@ -1668,6 +1676,60 @@ static int move2add_last_label_luid; || (GET_MODE_SIZE (OUTMODE) <= GET_MODE_SIZE (INMODE) \ && TRULY_NOOP_TRUNCATION_MODES_P (OUTMODE, INMODE))) +/* Record that REG is being set to a value with the mode of REG. */ + +static void +move2add_record_mode (rtx reg) +{ + int regno, nregs; + enum machine_mode mode = GET_MODE (reg); + + if (GET_CODE (reg) == SUBREG) + { + regno = subreg_regno (reg); + nregs = subreg_nregs (reg); + } + else if (REG_P (reg)) + { + regno = REGNO (reg); + nregs = hard_regno_nregs[regno][mode]; + } + else + gcc_unreachable (); + for (int i = nregs - 1; i > 0; i--) + reg_mode[regno + i] = BLKmode; + reg_mode[regno] = mode; +} + +/* Record that REG is being set to the sum of SYM and OFF. */ + +static void +move2add_record_sym_value (rtx reg, rtx sym, rtx off) +{ + int regno = REGNO (reg); + + move2add_record_mode (reg); + reg_set_luid[regno] = move2add_luid; + reg_base_reg[regno] = -1; + reg_symbol_ref[regno] = sym; + reg_offset[regno] = INTVAL (off); +} + +/* Check if REGNO contains a valid value in MODE. */ + +static bool +move2add_valid_value_p (int regno, enum machine_mode mode) +{ + if (reg_set_luid[regno] <= move2add_last_label_luid + || !MODES_OK_FOR_MOVE2ADD (mode, reg_mode[regno])) + return false; + + for (int i = hard_regno_nregs[regno][mode] - 1; i > 0; i--) + if (reg_mode[regno + i] != BLKmode) + return false; + return true; +} + /* This function is called with INSN that sets REG to (SYM + OFF), while REG is known to already have value (SYM + offset). This function tries to change INSN into an add instruction @@ -1743,11 +1805,7 @@ move2add_use_add2_insn (rtx reg, rtx sym } } } - reg_set_luid[regno] = move2add_luid; - reg_base_reg[regno] = -1; - reg_mode[regno] = GET_MODE (reg); - reg_symbol_ref[regno] = sym; - reg_offset[regno] = INTVAL (off); + move2add_record_sym_value (reg, sym, off); return changed; } @@ -1781,8 +1839,7 @@ move2add_use_add3_insn (rtx reg, rtx sym SET_SRC (pat) = plus_expr; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (reg_set_luid[i] > move2add_last_label_luid - && reg_mode[i] == GET_MODE (reg) + if (move2add_valid_value_p (i, GET_MODE (reg)) && reg_base_reg[i] < 0 && reg_symbol_ref[i] != NULL_RTX && rtx_equal_p (sym, reg_symbol_ref[i])) @@ -1830,10 +1887,7 @@ move2add_use_add3_insn (rtx reg, rtx sym changed = true; } reg_set_luid[regno] = move2add_luid; - reg_base_reg[regno] = -1; - reg_mode[regno] = GET_MODE (reg); - reg_symbol_ref[regno] = sym; - reg_offset[regno] = INTVAL (off); + move2add_record_sym_value (reg, sym, off); return changed; } @@ -1884,8 +1938,7 @@ reload_cse_move2add (rtx first) /* Check if we have valid information on the contents of this register in the mode of REG. */ - if (reg_set_luid[regno] > move2add_last_label_luid - && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), reg_mode[regno]) + if (move2add_valid_value_p (regno, GET_MODE (reg)) && dbg_cnt (cse2_move2add)) { /* Try to transform (set (REGX) (CONST_INT A)) @@ -1922,8 +1975,7 @@ reload_cse_move2add (rtx first) else if (REG_P (src) && reg_set_luid[regno] == reg_set_luid[REGNO (src)] && reg_base_reg[regno] == reg_base_reg[REGNO (src)] - && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), - reg_mode[REGNO (src)])) + && move2add_valid_value_p (REGNO (src), GET_MODE (reg))) { rtx next = next_nonnote_nondebug_insn (insn); rtx set = NULL_RTX; @@ -1976,10 +2028,10 @@ reload_cse_move2add (rtx first) delete_insn (insn); changed |= success; insn = next; - reg_mode[regno] = GET_MODE (reg); - reg_offset[regno] = - trunc_int_for_mode (added_offset + base_offset, - GET_MODE (reg)); + move2add_record_mode (reg); + reg_offset[regno] + = trunc_int_for_mode (added_offset + base_offset, + GET_MODE (reg)); continue; } } @@ -2015,8 +2067,7 @@ reload_cse_move2add (rtx first) /* If the reg already contains the value which is sum of sym and some constant value, we can use an add2 insn. */ - if (reg_set_luid[regno] > move2add_last_label_luid - && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), reg_mode[regno]) + if (move2add_valid_value_p (regno, GET_MODE (reg)) && reg_base_reg[regno] < 0 && reg_symbol_ref[regno] != NULL_RTX && rtx_equal_p (sym, reg_symbol_ref[regno])) @@ -2039,7 +2090,10 @@ reload_cse_move2add (rtx first) /* Reset the information about this register. */ int regno = REGNO (XEXP (note, 0)); if (regno < FIRST_PSEUDO_REGISTER) - reg_set_luid[regno] = 0; + { + move2add_record_mode (XEXP (note, 0)); + reg_mode[regno] = VOIDmode; + } } } note_stores (PATTERN (insn), move2add_note_store, insn); @@ -2076,7 +2130,7 @@ reload_cse_move2add (rtx first) { if (call_used_regs[i]) /* Reset the information about this register. */ - reg_set_luid[i] = 0; + reg_mode[i] = VOIDmode; } } } @@ -2093,20 +2147,8 @@ move2add_note_store (rtx dst, const_rtx { rtx insn = (rtx) data; unsigned int regno = 0; - unsigned int nregs = 0; - unsigned int i; enum machine_mode mode = GET_MODE (dst); - if (GET_CODE (dst) == SUBREG) - { - regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)), - GET_MODE (SUBREG_REG (dst)), - SUBREG_BYTE (dst), - GET_MODE (dst)); - nregs = subreg_nregs (dst); - dst = SUBREG_REG (dst); - } - /* Some targets do argument pushes without adding REG_INC notes. */ if (MEM_P (dst)) @@ -2114,27 +2156,28 @@ move2add_note_store (rtx dst, const_rtx dst = XEXP (dst, 0); if (GET_CODE (dst) == PRE_INC || GET_CODE (dst) == POST_INC || GET_CODE (dst) == PRE_DEC || GET_CODE (dst) == POST_DEC) - reg_set_luid[REGNO (XEXP (dst, 0))] = 0; + reg_mode[REGNO (XEXP (dst, 0))] = VOIDmode; return; } - if (!REG_P (dst)) - return; - regno += REGNO (dst); - if (!nregs) - nregs = hard_regno_nregs[regno][mode]; + if (GET_CODE (dst) == SUBREG) + regno = subreg_regno (dst); + else if (REG_P (dst)) + regno = REGNO (dst); + else + return; - if (SCALAR_INT_MODE_P (GET_MODE (dst)) - && nregs == 1 && GET_CODE (set) == SET) + if (SCALAR_INT_MODE_P (mode) + && GET_CODE (set) == SET) { rtx note, sym = NULL_RTX; - HOST_WIDE_INT off; + rtx off; note = find_reg_equal_equiv_note (insn); if (note && GET_CODE (XEXP (note, 0)) == SYMBOL_REF) { sym = XEXP (note, 0); - off = 0; + off = const0_rtx; } else if (note && GET_CODE (XEXP (note, 0)) == CONST && GET_CODE (XEXP (XEXP (note, 0), 0)) == PLUS @@ -2142,22 +2185,18 @@ move2add_note_store (rtx dst, const_rtx && CONST_INT_P (XEXP (XEXP (XEXP (note, 0), 0), 1))) { sym = XEXP (XEXP (XEXP (note, 0), 0), 0); - off = INTVAL (XEXP (XEXP (XEXP (note, 0), 0), 1)); + off = XEXP (XEXP (XEXP (note, 0), 0), 1); } if (sym != NULL_RTX) { - reg_base_reg[regno] = -1; - reg_symbol_ref[regno] = sym; - reg_offset[regno] = off; - reg_mode[regno] = mode; - reg_set_luid[regno] = move2add_luid; + move2add_record_sym_value (dst, sym, off); return; } } - if (SCALAR_INT_MODE_P (GET_MODE (dst)) - && nregs == 1 && GET_CODE (set) == SET + if (SCALAR_INT_MODE_P (mode) + && GET_CODE (set) == SET && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART) { @@ -2165,9 +2204,6 @@ move2add_note_store (rtx dst, const_rtx rtx base_reg; HOST_WIDE_INT offset; int base_regno; - /* This may be different from mode, if SET_DEST (set) is a - SUBREG. */ - enum machine_mode dst_mode = GET_MODE (dst); switch (GET_CODE (src)) { @@ -2179,20 +2215,14 @@ move2add_note_store (rtx dst, const_rtx if (CONST_INT_P (XEXP (src, 1))) offset = INTVAL (XEXP (src, 1)); else if (REG_P (XEXP (src, 1)) - && (reg_set_luid[REGNO (XEXP (src, 1))] - > move2add_last_label_luid) - && (MODES_OK_FOR_MOVE2ADD - (dst_mode, reg_mode[REGNO (XEXP (src, 1))]))) + && move2add_valid_value_p (REGNO (XEXP (src, 1)), mode)) { if (reg_base_reg[REGNO (XEXP (src, 1))] < 0 && reg_symbol_ref[REGNO (XEXP (src, 1))] == NULL_RTX) offset = reg_offset[REGNO (XEXP (src, 1))]; /* Maybe the first register is known to be a constant. */ - else if (reg_set_luid[REGNO (base_reg)] - > move2add_last_label_luid - && (MODES_OK_FOR_MOVE2ADD - (dst_mode, reg_mode[REGNO (base_reg)])) + else if (move2add_valid_value_p (REGNO (base_reg), mode) && reg_base_reg[REGNO (base_reg)] < 0 && reg_symbol_ref[REGNO (base_reg)] == NULL_RTX) { @@ -2222,33 +2252,26 @@ move2add_note_store (rtx dst, const_rtx reg_offset[regno] = INTVAL (SET_SRC (set)); /* We assign the same luid to all registers set to constants. */ reg_set_luid[regno] = move2add_last_label_luid + 1; - reg_mode[regno] = mode; + move2add_record_mode (dst); return; default: - invalidate: - /* Invalidate the contents of the register. */ - reg_set_luid[regno] = 0; - return; + goto invalidate; } base_regno = REGNO (base_reg); /* If information about the base register is not valid, set it up as a new base register, pretending its value is known starting from the current insn. */ - if (reg_set_luid[base_regno] <= move2add_last_label_luid) + if (!move2add_valid_value_p (base_regno, mode)) { reg_base_reg[base_regno] = base_regno; reg_symbol_ref[base_regno] = NULL_RTX; reg_offset[base_regno] = 0; reg_set_luid[base_regno] = move2add_luid; - reg_mode[base_regno] = mode; + gcc_assert (GET_MODE (base_reg) == mode); + move2add_record_mode (base_reg); } - else if (! MODES_OK_FOR_MOVE2ADD (dst_mode, - reg_mode[base_regno])) - goto invalidate; - - reg_mode[regno] = mode; /* Copy base information from our base register. */ reg_set_luid[regno] = reg_set_luid[base_regno]; @@ -2256,17 +2279,17 @@ move2add_note_store (rtx dst, const_rtx reg_symbol_ref[regno] = reg_symbol_ref[base_regno]; /* Compute the sum of the offsets or constants. */ - reg_offset[regno] = trunc_int_for_mode (offset - + reg_offset[base_regno], - dst_mode); + reg_offset[regno] + = trunc_int_for_mode (offset + reg_offset[base_regno], mode); + + move2add_record_mode (dst); } else { - unsigned int endregno = regno + nregs; - - for (i = regno; i < endregno; i++) - /* Reset the information about this register. */ - reg_set_luid[i] = 0; + invalidate: + /* Invalidate the contents of the register. */ + move2add_record_mode (dst); + reg_mode[regno] = VOIDmode; } }