The following patch fixes a new crash on SPEC2000 sixtrack on x86-64. LRA failed to find a mode for a constant. When LRA can not find a mode of operand it uses mode from machine description of the insn. It is not enough, in very rare cases the mode can be found only from context. The patch adds such code.

The patch was successfully bootstrapped on x86-64.

2011-08-03  Vladimir Makarov <vmaka...@redhat.com>

        * lra-int.h (lra_get_mode): Remove.

        * lra-constraints.c (find_mode, get_op_mode): New.
        (match_reload, curr_insn_transform, process_alt_operands): Use
        get_op_mode instead of lra_get_mode.

Index: lra-int.h
===================================================================
--- lra-int.h   (revision 176797)
+++ lra-int.h   (working copy)
@@ -225,16 +225,6 @@ struct lra_insn_recog_data
 
 typedef struct lra_insn_recog_data *lra_insn_recog_data_t;
 
-/* Return mode for X which corresponds to machine description operand
-   with mode MD_MODE.  */
-static inline enum machine_mode
-lra_get_mode (enum machine_mode md_mode, rtx x)
-{
-  if (GET_MODE (x) != VOIDmode)
-    return GET_MODE (x);
-  return md_mode;
-}
-
 /* lra.c: */
 
 extern FILE *lra_dump_file;
Index: lra-constraints.c
===================================================================
--- lra-constraints.c   (revision 176950)
+++ lra-constraints.c   (working copy)
@@ -786,6 +786,60 @@ bitmap_head lra_dont_inherit_pseudos;
   (reg_class_size [(C)] == 1                                           \
    || (reg_class_size [(C)] >= 1 && targetm.class_likely_spilled_p (C)))
 
+/* Return mode of WHAT inside of WHERE whose mode of the context is
+   OUTER_MODE.  If WHERE does not contain WHAT, return VOIDmode.  */
+static enum machine_mode
+find_mode (rtx *where, enum machine_mode outer_mode, rtx *what)
+{
+  int i, j;
+  enum machine_mode mode;
+  rtx x;
+  const char *fmt;
+  enum rtx_code code;
+
+  if (where == what)
+    return outer_mode;
+  if (*where == NULL_RTX)
+    return VOIDmode;
+  x = *where;
+  code = GET_CODE (x);
+  outer_mode = GET_MODE (x);
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       {
+         if ((mode = find_mode (&XEXP (x, i), outer_mode, what)) != VOIDmode)
+           return mode;
+       }
+      else if (fmt[i] == 'E')
+       {
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         if ((mode = find_mode (&XVECEXP (x, i, j), outer_mode, what))
+             != VOIDmode)
+           return mode;
+       }
+    }
+  return VOIDmode;
+}
+
+/* Return mode for operand NOP of the current insn.  */
+static inline enum machine_mode
+get_op_mode (int nop)
+{
+  rtx *loc = curr_id->operand_loc[nop];
+  enum machine_mode mode = GET_MODE (*loc);
+
+  /* Take mode from the operand first.  */
+  if (mode != VOIDmode)
+    return mode;
+  /* Take mode from the machine description second.  */
+  if ((mode = curr_static_id->operand[nop].mode) != VOIDmode)
+    return mode;
+  /* Here is a very rare case.  Take mode from the context.  */
+  return find_mode (&PATTERN (curr_insn), VOIDmode, loc);
+}
+
 /* Generate reloads for matching OUT and IN with reg class GOAL_CLASS.
    Add input and output reloads correspondingly to the lists *BEFORE
    and *AFTER.  */
@@ -798,8 +852,8 @@ match_reload (int out, int in, enum reg_
   rtx in_rtx = *curr_id->operand_loc[in];
   rtx out_rtx = *curr_id->operand_loc[out];
 
-  inmode = lra_get_mode (curr_static_id->operand[in].mode, in_rtx);
-  outmode = lra_get_mode (curr_static_id->operand[out].mode, out_rtx);
+  inmode = get_op_mode (in);
+  outmode = get_op_mode (out);
   if (inmode != outmode)
     {
       /* Don't reuse the pseudos for inheritance -- they will be bound.  */
@@ -1897,8 +1951,7 @@ process_alt_operands (int only_alternati
                  && ((targetm.preferred_reload_class
                       (op, this_alternative) == NO_REGS)
                      || no_input_reloads_p)
-                 && lra_get_mode (curr_static_id->operand[nop].mode,
-                                  op) != VOIDmode)
+                 && get_op_mode (nop) != VOIDmode)
                {
                  const_to_mem = 1;
                  if (! no_regs_p)
@@ -2807,8 +2860,7 @@ curr_insn_transform (void)
        rtx op = *curr_id->operand_loc[i];
        rtx subreg = NULL_RTX;
        rtx plus = NULL_RTX;
-       enum machine_mode mode
-         = lra_get_mode (curr_static_id->operand[i].mode, op);
+       enum machine_mode mode = get_op_mode (i);
        
        if (GET_CODE (op) == SUBREG)
          {
@@ -2921,7 +2973,7 @@ curr_insn_transform (void)
          enum op_type type = curr_static_id->operand[i].type;
 
          loc = curr_id->operand_loc[i];
-         mode = lra_get_mode (curr_static_id->operand[i].mode, *loc);
+         mode = get_op_mode (i);
          if (GET_CODE (*loc) == SUBREG)
            {
              reg = SUBREG_REG (*loc);

Reply via email to