diff --git a/gcc/combine.c b/gcc/combine.c index 62bf4aeaaba..6ef6a08d54f 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -202,6 +202,12 @@ struct reg_stat_type { int last_set_table_tick; + /* Record the luid of the insn which uses register n, the insn should + be the first one using register n in that block of the insn which + last_set_table_tick was set for. */ + + int last_set_table_luid; + /* Record the value of label_tick when the value for register n is placed in last_set_value. */ @@ -476,7 +482,6 @@ static rtx gen_lowpart_for_combine (machine_mode, rtx); static enum rtx_code simplify_compare_const (enum rtx_code, machine_mode, rtx, rtx *); static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *); -static void update_table_tick (rtx); static void record_value_for_reg (rtx, rtx_insn *, rtx); static void check_promoted_subreg (rtx_insn *, rtx); static void record_dead_and_set_regs_1 (rtx, const_rtx, void *); @@ -13179,7 +13184,7 @@ count_rtxs (rtx x) for each register mentioned. Similar to mention_regs in cse.c */ static void -update_table_tick (rtx x) +update_table_tick (rtx x, int insn_luid) { enum rtx_code code = GET_CODE (x); const char *fmt = GET_RTX_FORMAT (code); @@ -13194,7 +13199,27 @@ update_table_tick (rtx x) for (r = regno; r < endregno; r++) { reg_stat_type *rsp = ®_stat[r]; - rsp->last_set_table_tick = label_tick; + if (rsp->last_set_table_tick >= label_tick_ebb_start) + { + /* Later references should not have lower ticks. */ + gcc_assert (label_tick >= rsp->last_set_table_tick); + /* Since combination may generate some instructions + to replace some foregoing instructions with the + references to register r (using register r), we + need to make sure we record the first instruction + which is using register r, so always update with + the lowest luid here. If the given set happens + before this recorded earliest reference, the set + value should be safe to be used. */ + if (label_tick == rsp->last_set_table_tick + && rsp->last_set_table_luid > insn_luid) + rsp->last_set_table_luid = insn_luid; + } + else + { + rsp->last_set_table_tick = label_tick; + rsp->last_set_table_luid = insn_luid; + } } return; @@ -13230,16 +13255,17 @@ update_table_tick (rtx x) if (ARITHMETIC_P (x0) && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1))) { - update_table_tick (XEXP (x0, x1 == XEXP (x0, 0) ? 1 : 0)); + update_table_tick (XEXP (x0, x1 == XEXP (x0, 0) ? 1 : 0), + insn_luid); break; } } - update_table_tick (XEXP (x, i)); + update_table_tick (XEXP (x, i), insn_luid); } else if (fmt[i] == 'E') for (j = 0; j < XVECLEN (x, i); j++) - update_table_tick (XVECEXP (x, i, j)); + update_table_tick (XVECEXP (x, i, j), insn_luid); } /* Record that REG is set to VALUE in insn INSN. If VALUE is zero, we @@ -13310,21 +13336,26 @@ record_value_for_reg (rtx reg, rtx_insn *insn, rtx value) /* Mark registers that are being referenced in this value. */ if (value) - update_table_tick (value); + update_table_tick (value, DF_INSN_LUID (insn)); /* Now update the status of each register being set. If someone is using this register in this block, set this register to invalid since we will get confused between the two lives in this basic block. This makes using this register always invalid. In cse, we scan the table to invalidate all entries using this register, but this - is too much work for us. */ + is too much work for us. If we know this register set and its register + uses are in the same block, and the set always happens before any uses, + we don't need to make it invalid. */ for (i = regno; i < endregno; i++) { rsp = ®_stat[i]; rsp->last_set_label = label_tick; + gcc_assert (label_tick >= rsp->last_set_table_tick); if (!insn - || (value && rsp->last_set_table_tick >= label_tick_ebb_start)) + || (value && rsp->last_set_table_tick >= label_tick_ebb_start + && !(label_tick == rsp->last_set_table_tick + && DF_INSN_LUID (insn) < rsp->last_set_table_luid))) rsp->last_set_invalid = 1; else rsp->last_set_invalid = 0;