aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorVladimir Makarov <vmakarov@redhat.com>2008-10-16 00:51:34 +0000
committerVladimir Makarov <vmakarov@gcc.gnu.org>2008-10-16 00:51:34 +0000
commit22c02455bf65c6cec3bf1d7a69439de949fdc76e (patch)
tree98630eeb409712d9d59c071d3d4c9376d77c509a /gcc
parent0ca9fa56e9c0eb900efe8106d3c85153b902da8f (diff)
downloadgcc-22c02455bf65c6cec3bf1d7a69439de949fdc76e.zip
gcc-22c02455bf65c6cec3bf1d7a69439de949fdc76e.tar.gz
gcc-22c02455bf65c6cec3bf1d7a69439de949fdc76e.tar.bz2
re PR middle-end/37535 (gcc/libgcc2.c:404: internal compiler error: Floating point exception)
2008-10-15 Vladimir Makarov <vmakarov@redhat.com> PR middle-end/37535 * ira-lives.c (mark_early_clobbers): Remove. (make_pseudo_conflict, check_and_make_def_use_conflicts, check_and_make_def_conflicts, make_early_clobber_and_input_conflicts, mark_hard_reg_early_clobbers): New functions. (process_bb_node_lives): Call make_early_clobber_and_input_conflicts and mark_hard_reg_early_clobbers. Make hard register inputs live again. * doc/rtl.texi (clobber): Change descriotion of RA behaviour for early clobbers of pseudo-registers. From-SVN: r141160
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/doc/rtl.texi11
-rw-r--r--gcc/ira-lives.c201
3 files changed, 193 insertions, 35 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0cf0dec..68ae6ec 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,21 @@
2008-10-15 Vladimir Makarov <vmakarov@redhat.com>
+ PR middle-end/37535
+ * ira-lives.c (mark_early_clobbers): Remove.
+ (make_pseudo_conflict, check_and_make_def_use_conflicts,
+ check_and_make_def_conflicts,
+ make_early_clobber_and_input_conflicts,
+ mark_hard_reg_early_clobbers): New functions.
+ (process_bb_node_lives): Call
+ make_early_clobber_and_input_conflicts and
+ mark_hard_reg_early_clobbers. Make hard register inputs live
+ again.
+
+ * doc/rtl.texi (clobber): Change descriotion of RA behaviour for
+ early clobbers of pseudo-registers.
+
+2008-10-15 Vladimir Makarov <vmakarov@redhat.com>
+
PR middle-end/37674
* ira-build.c (ira_flattening): Recalculate
ALLOCNO_TOTAL_NO_STACK_REG_P and ALLOCNO_TOTAL_CONFLICT_HARD_REGS
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 701e490..1411f24 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -2917,11 +2917,12 @@ constituent instructions might not.
When a @code{clobber} expression for a register appears inside a
@code{parallel} with other side effects, the register allocator
guarantees that the register is unoccupied both before and after that
-insn if it is a hard register clobber or the @samp{&} constraint
-is specified for at least one alternative (@pxref{Modifiers}) of the
-clobber. However, the reload phase may allocate a register used for
-one of the inputs unless the @samp{&} constraint is specified for the
-selected alternative. You can clobber either a specific hard
+insn if it is a hard register clobber. For pseudo-register clobber,
+the register allocator and the reload pass do not assign the same hard
+register to the clobber and the input operands if there is an insn
+alternative containing the @samp{&} constraint (@pxref{Modifiers}) for
+the clobber and the hard register is in register classes of the
+clobber in the alternative. You can clobber either a specific hard
register, a pseudo register, or a @code{scratch} expression; in the
latter two cases, GCC will allocate a hard register that is available
there for use as a temporary.
diff --git a/gcc/ira-lives.c b/gcc/ira-lives.c
index 89343fe..f4b2d6d 100644
--- a/gcc/ira-lives.c
+++ b/gcc/ira-lives.c
@@ -349,39 +349,169 @@ mark_ref_dead (df_ref def)
mark_reg_dead (reg);
}
-/* Mark early clobber registers of the current INSN as live (if
- LIVE_P) or dead. Return true if there are such registers. */
+/* Make pseudo REG conflicting with pseudo DREG, if the 1st pseudo
+ class is intersected with class CL. Advance the current program
+ point before making the conflict if ADVANCE_P. Return TRUE if we
+ will need to advance the current program point. */
static bool
-mark_early_clobbers (rtx insn, bool live_p)
+make_pseudo_conflict (rtx reg, enum reg_class cl, rtx dreg, bool advance_p)
{
- int alt;
- int def;
- df_ref *def_rec;
- bool set_p = false;
+ ira_allocno_t a;
- for (def = 0; def < recog_data.n_operands; def++)
- {
- rtx dreg = recog_data.operand[def];
-
- if (GET_CODE (dreg) == SUBREG)
- dreg = SUBREG_REG (dreg);
- if (! REG_P (dreg))
- continue;
+ if (GET_CODE (reg) == SUBREG)
+ reg = SUBREG_REG (reg);
+
+ if (! REG_P (reg) || REGNO (reg) < FIRST_PSEUDO_REGISTER)
+ return advance_p;
+
+ a = ira_curr_regno_allocno_map[REGNO (reg)];
+ if (! reg_classes_intersect_p (cl, ALLOCNO_COVER_CLASS (a)))
+ return advance_p;
- for (alt = 0; alt < recog_data.n_alternatives; alt++)
- if ((recog_op_alt[def][alt].earlyclobber)
- && (recog_op_alt[def][alt].cl != NO_REGS))
- break;
+ if (advance_p)
+ curr_point++;
- if (alt >= recog_data.n_alternatives)
- continue;
+ mark_reg_live (reg);
+ mark_reg_live (dreg);
+ mark_reg_dead (reg);
+ mark_reg_dead (dreg);
+
+ return false;
+}
- if (live_p)
- mark_reg_live (dreg);
+/* Check and make if necessary conflicts for pseudo DREG of class
+ DEF_CL of the current insn with input operand USE of class USE_CL.
+ Advance the current program point before making the conflict if
+ ADVANCE_P. Return TRUE if we will need to advance the current
+ program point. */
+static bool
+check_and_make_def_use_conflict (rtx dreg, enum reg_class def_cl,
+ int use, enum reg_class use_cl,
+ bool advance_p)
+{
+ if (! reg_classes_intersect_p (def_cl, use_cl))
+ return advance_p;
+
+ advance_p = make_pseudo_conflict (recog_data.operand[use],
+ use_cl, dreg, advance_p);
+ /* Reload may end up swapping commutative operands, so you
+ have to take both orderings into account. The
+ constraints for the two operands can be completely
+ different. (Indeed, if the constraints for the two
+ operands are the same for all alternatives, there's no
+ point marking them as commutative.) */
+ if (use < recog_data.n_operands + 1
+ && recog_data.constraints[use][0] == '%')
+ advance_p
+ = make_pseudo_conflict (recog_data.operand[use + 1],
+ use_cl, dreg, advance_p);
+ if (use >= 1
+ && recog_data.constraints[use - 1][0] == '%')
+ advance_p
+ = make_pseudo_conflict (recog_data.operand[use - 1],
+ use_cl, dreg, advance_p);
+ return advance_p;
+}
+
+/* Check and make if necessary conflicts for definition DEF of class
+ DEF_CL of the current insn with input operands. Process only
+ constraints of alternative ALT. */
+static void
+check_and_make_def_conflict (int alt, int def, enum reg_class def_cl)
+{
+ int use, use_match;
+ ira_allocno_t a;
+ enum reg_class use_cl, acl;
+ bool advance_p;
+ rtx dreg = recog_data.operand[def];
+
+ if (def_cl == NO_REGS)
+ return;
+
+ if (GET_CODE (dreg) == SUBREG)
+ dreg = SUBREG_REG (dreg);
+
+ if (! REG_P (dreg) || REGNO (dreg) < FIRST_PSEUDO_REGISTER)
+ return;
+
+ a = ira_curr_regno_allocno_map[REGNO (dreg)];
+ acl = ALLOCNO_COVER_CLASS (a);
+ if (! reg_classes_intersect_p (acl, def_cl))
+ return;
+
+ advance_p = true;
+
+ for (use = 0; use < recog_data.n_operands; use++)
+ {
+ if (use == def || recog_data.operand_type[use] == OP_OUT)
+ return;
+
+ if (recog_op_alt[use][alt].anything_ok)
+ use_cl = ALL_REGS;
else
- mark_reg_dead (dreg);
- set_p = true;
+ use_cl = recog_op_alt[use][alt].cl;
+
+ advance_p = check_and_make_def_use_conflict (dreg, def_cl, use,
+ use_cl, advance_p);
+
+ if ((use_match = recog_op_alt[use][alt].matches) >= 0)
+ {
+ if (use_match == def)
+ return;
+
+ if (recog_op_alt[use_match][alt].anything_ok)
+ use_cl = ALL_REGS;
+ else
+ use_cl = recog_op_alt[use_match][alt].cl;
+ advance_p = check_and_make_def_use_conflict (dreg, def_cl, use,
+ use_cl, advance_p);
+ }
}
+}
+
+/* Make conflicts of early clobber pseudo registers of the current
+ insn with its inputs. Avoid introducing unnecessary conflicts by
+ checking classes of the constraints and pseudos because otherwise
+ significant code degradation is possible for some targets. */
+static void
+make_early_clobber_and_input_conflicts (void)
+{
+ int alt;
+ int def, def_match;
+ enum reg_class def_cl;
+
+ for (alt = 0; alt < recog_data.n_alternatives; alt++)
+ for (def = 0; def < recog_data.n_operands; def++)
+ {
+ def_cl = NO_REGS;
+ if (recog_op_alt[def][alt].earlyclobber)
+ {
+ if (recog_op_alt[def][alt].anything_ok)
+ def_cl = ALL_REGS;
+ else
+ def_cl = recog_op_alt[def][alt].cl;
+ check_and_make_def_conflict (alt, def, def_cl);
+ }
+ if ((def_match = recog_op_alt[def][alt].matches) >= 0
+ && (recog_op_alt[def_match][alt].earlyclobber
+ || recog_op_alt[def][alt].earlyclobber))
+ {
+ if (recog_op_alt[def_match][alt].anything_ok)
+ def_cl = ALL_REGS;
+ else
+ def_cl = recog_op_alt[def_match][alt].cl;
+ check_and_make_def_conflict (alt, def, def_cl);
+ }
+ }
+}
+
+/* Mark early clobber hard registers of the current INSN as live (if
+ LIVE_P) or dead. Return true if there are such registers. */
+static bool
+mark_hard_reg_early_clobbers (rtx insn, bool live_p)
+{
+ df_ref *def_rec;
+ bool set_p = false;
for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
if (DF_REF_FLAGS_IS_SET (*def_rec, DF_REF_MUST_CLOBBER))
@@ -792,25 +922,36 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
}
}
+ make_early_clobber_and_input_conflicts ();
+
curr_point++;
/* Mark each used value as live. */
for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
mark_ref_live (*use_rec);
- set_p = mark_early_clobbers (insn, true);
-
process_single_reg_class_operands (true, freq);
+ set_p = mark_hard_reg_early_clobbers (insn, true);
+
if (set_p)
{
- mark_early_clobbers (insn, false);
+ mark_hard_reg_early_clobbers (insn, false);
- /* Mark each used value as live again. For example, a
+ /* Mark each hard reg as live again. For example, a
hard register can be in clobber and in an insn
input. */
for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
- mark_ref_live (*use_rec);
+ {
+ rtx ureg = DF_REF_REG (*use_rec);
+
+ if (GET_CODE (ureg) == SUBREG)
+ ureg = SUBREG_REG (ureg);
+ if (! REG_P (ureg) || REGNO (ureg) >= FIRST_PSEUDO_REGISTER)
+ continue;
+
+ mark_ref_live (*use_rec);
+ }
}
curr_point++;