[backport gcc-4.9/trunk r198204 ] List-Archive: Mon, 15 Apr 2013 05:20:06 +0000 Subject: LRA assign same hard register with live range overlapped pseduos From: shiva Chen HI, I'm trying to port a new 32bit target to GCC 4.8.0 with LRA enabled There is an error case which generates following RTL (insn 536 267 643 3 (set (reg/f:SI 0 $r0 [477]) <== r477 assign to r0 (plus:SI (reg/f:SI 31 $sp) (const_int 112 [0x70]))) test2.c:95 64 {*addsi3} (nil)) (insn 643 536 537 3 (set (reg/f:SI 0 $r0 [565]) <== r565 assign to r0, and corrupt the usage of r477 (reg/f:SI 31 $sp)) test2.c:95 44 {*movsi} (nil)) (insn 537 643 538 3 (set (reg/v:SI 13 $r13 [orig:61 i14 ] [61]) (mem/c:SI (plus:SI (reg/f:SI 0 $r0 [565]) <== use r565 (const_int 136 [0x88])) [5 %sfp+24 S4 A32])) test2.c:95 39 {*load_si} (expr_list:REG_DEAD (reg/f:SI 0 $r0 [565]) (nil))) ... (insn 539 540 270 3 (set (reg:SI 0 $r0 [479]) (plus:SI (reg/f:SI 0 $r0 [477]) (reg:SI 5 $r5 [480]))) test2.c:95 62 {*add_16bit} (expr_list:REG_DEAD (reg:SI 5 $r5 [480]) (expr_list:REG_DEAD (reg/f:SI 0 $r0 [477]) <== use r477 which should be $sp +112 Note that the live ranges of r477 and r565 are overlapped but assigned same register $r0. (r31 is stack pointer) By tracing LRA process, I noticed that when r477 is created, the lra_reg_info[r477].val = lra_reg_info[r31] due to (set r477 r31). But after lra_eliminate(), the stack offset changes and r477 is equal to r31+112 instead. In next lra-iteration round, r565 is created, and r565 = r31. In that case, register content of r477 should treat as not equal to r565 due to eliminate offset have been changed. Otherwise, r565 and r477 may assign to same hard register. To recognize that, I record the eliminate offset when the pseudo register have been created. Register content are the same only when lra_reg_info[].val and lra_reg_info[].offset are equal. List-Archive: Date: Tue, 23 Apr 2013 13:32:16 -0400 From: Vladimir Makarov Subject: a lra patch The following patch is Shiva Chen's patch to fix a LRA bug on some experimental target. The bug occurs when one insn requires many reloads and they are done on different passes. I evaluate the probability of this bug for other targets as quite tiny. The patch was approved by me. Successfully bootstrapped on x86/x86-64. Committed as rev. 198204. gcc/ 2013-04-23 Shiva Chen * lra-assigns.c (find_hard_regno_for): Use lra_reg_val_equal_p to check the register content is equal or not. * lra-constraints.c (match_reload): Use lra_assign_reg_val to assign register content record. * lra-eliminations.c (update_reg_eliminate): Use lra_update_reg_val_offset to update register content offset. * lra-int.h (struct lra_reg): Add offset member. (lra_reg_val_equal_p): New static inline function. (lra_update_reg_val_offset): New static inline function. (lra_assign_reg_val): New static inline function. * lra.c (lra_create_new_reg): Use lra_assign_reg_val to assign register content record. (initialize_lra_reg_info_element): Initial offset to zero. --- gcc-4.8.0/gcc/lra-assigns.c.~1~ 2013-02-15 20:17:02.000000000 +0100 +++ gcc-4.8.0/gcc/lra-assigns.c 2013-04-27 15:57:01.555523961 +0200 @@ -448,7 +448,7 @@ find_hard_regno_for (int regno, int *cos int hr, conflict_hr, nregs; enum machine_mode biggest_mode; unsigned int k, conflict_regno; - int val, biggest_nregs, nregs_diff; + int offset, val, biggest_nregs, nregs_diff; enum reg_class rclass; bitmap_iterator bi; bool *rclass_intersect_p; @@ -508,9 +508,10 @@ find_hard_regno_for (int regno, int *cos #endif sparseset_clear_bit (conflict_reload_and_inheritance_pseudos, regno); val = lra_reg_info[regno].val; + offset = lra_reg_info[regno].offset; CLEAR_HARD_REG_SET (impossible_start_hard_regs); EXECUTE_IF_SET_IN_SPARSESET (live_range_hard_reg_pseudos, conflict_regno) - if (val == lra_reg_info[conflict_regno].val) + if (lra_reg_val_equal_p (conflict_regno, val, offset)) { conflict_hr = live_pseudos_reg_renumber[conflict_regno]; nregs = (hard_regno_nregs[conflict_hr] @@ -538,7 +539,7 @@ find_hard_regno_for (int regno, int *cos } EXECUTE_IF_SET_IN_SPARSESET (conflict_reload_and_inheritance_pseudos, conflict_regno) - if (val != lra_reg_info[conflict_regno].val) + if (!lra_reg_val_equal_p (conflict_regno, val, offset)) { lra_assert (live_pseudos_reg_renumber[conflict_regno] < 0); if ((hard_regno @@ -1007,7 +1008,7 @@ setup_live_pseudos_and_spill_after_risky { int p, i, j, n, regno, hard_regno; unsigned int k, conflict_regno; - int val; + int val, offset; HARD_REG_SET conflict_set; enum machine_mode mode; lra_live_range_t r; @@ -1050,8 +1051,9 @@ setup_live_pseudos_and_spill_after_risky COPY_HARD_REG_SET (conflict_set, lra_no_alloc_regs); IOR_HARD_REG_SET (conflict_set, lra_reg_info[regno].conflict_hard_regs); val = lra_reg_info[regno].val; + offset = lra_reg_info[regno].offset; EXECUTE_IF_SET_IN_SPARSESET (live_range_hard_reg_pseudos, conflict_regno) - if (val != lra_reg_info[conflict_regno].val + if (!lra_reg_val_equal_p (conflict_regno, val, offset) /* If it is multi-register pseudos they should start on the same hard register. */ || hard_regno != reg_renumber[conflict_regno]) --- gcc-4.8.0/gcc/lra-constraints.c.~1~ 2013-02-22 17:30:22.000000000 +0100 +++ gcc-4.8.0/gcc/lra-constraints.c 2013-04-27 15:57:01.555523961 +0200 @@ -704,7 +704,7 @@ match_reload (signed char out, signed ch pseudos still live where reload pseudos dies. */ if (REG_P (in_rtx) && (int) REGNO (in_rtx) < lra_new_regno_start && find_regno_note (curr_insn, REG_DEAD, REGNO (in_rtx))) - lra_reg_info[REGNO (reg)].val = lra_reg_info[REGNO (in_rtx)].val; + lra_assign_reg_val (REGNO (in_rtx), REGNO (reg)); } else { @@ -733,8 +733,7 @@ match_reload (signed char out, signed ch && GET_MODE (subreg_reg) == outmode && SUBREG_BYTE (in_rtx) == SUBREG_BYTE (new_in_reg) && find_regno_note (curr_insn, REG_DEAD, REGNO (subreg_reg))) - lra_reg_info[REGNO (reg)].val - = lra_reg_info[REGNO (subreg_reg)].val; + lra_assign_reg_val (REGNO (subreg_reg), REGNO (reg)); } } } --- gcc-4.8.0/gcc/lra-eliminations.c.~1~ 2013-01-10 21:38:27.000000000 +0100 +++ gcc-4.8.0/gcc/lra-eliminations.c 2013-04-27 15:57:01.555523961 +0200 @@ -1124,8 +1124,15 @@ update_reg_eliminate (bitmap insns_with_ setup_elimination_map (); for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) if (elimination_map[ep->from] == ep && ep->previous_offset != ep->offset) - bitmap_ior_into (insns_with_changed_offsets, - &lra_reg_info[ep->from].insn_bitmap); + { + bitmap_ior_into (insns_with_changed_offsets, + &lra_reg_info[ep->from].insn_bitmap); + + /* Update offset when the eliminate offset have been + changed. */ + lra_update_reg_val_offset (lra_reg_info[ep->from].val, + ep->offset - ep->previous_offset); + } } /* Initialize the table of hard registers to eliminate. --- gcc-4.8.0/gcc/lra-int.h.~1~ 2013-01-10 21:38:27.000000000 +0100 +++ gcc-4.8.0/gcc/lra-int.h 2013-04-27 15:57:01.555523961 +0200 @@ -116,6 +116,8 @@ struct lra_reg /* Value holding by register. If the pseudos have the same value they do not conflict. */ int val; + /* Offset from relative eliminate register to pesudo reg. */ + int offset; /* These members are set up in lra-lives.c and updated in lra-coalesce.c. */ /* The biggest size mode in which each pseudo reg is referred in @@ -439,6 +441,37 @@ lra_get_insn_recog_data (rtx insn) return lra_set_insn_recog_data (insn); } +/* Update offset from pseudos with VAL by INCR. */ +static inline void +lra_update_reg_val_offset (int val, int incr) +{ + int i; + + for (i = FIRST_PSEUDO_REGISTER; i < max_reg_num (); i++) + { + if (lra_reg_info[i].val == val) + lra_reg_info[i].offset += incr; + } +} + +/* Return true if register content is equal to VAL with OFFSET. */ +static inline bool +lra_reg_val_equal_p (int regno, int val, int offset) +{ + if (lra_reg_info[regno].val == val + && lra_reg_info[regno].offset == offset) + return true; + + return false; +} + +/* Assign value of register FROM to TO. */ +static inline void +lra_assign_reg_val (int from, int to) +{ + lra_reg_info[to].val = lra_reg_info[from].val; + lra_reg_info[to].offset = lra_reg_info[from].offset; +} struct target_lra_int --- gcc-4.8.0/gcc/lra.c.~1~ 2013-03-05 16:50:38.000000000 +0100 +++ gcc-4.8.0/gcc/lra.c 2013-04-27 15:57:01.555523961 +0200 @@ -194,7 +194,7 @@ lra_create_new_reg (enum machine_mode md new_reg = lra_create_new_reg_with_unique_value (md_mode, original, rclass, title); if (original != NULL_RTX && REG_P (original)) - lra_reg_info[REGNO (new_reg)].val = lra_reg_info[REGNO (original)].val; + lra_assign_reg_val (REGNO (original), REGNO (new_reg)); return new_reg; } @@ -1392,6 +1392,7 @@ initialize_lra_reg_info_element (int i) lra_reg_info[i].last_reload = 0; lra_reg_info[i].restore_regno = -1; lra_reg_info[i].val = get_new_reg_value (); + lra_reg_info[i].offset = 0; lra_reg_info[i].copies = NULL; }