Fix checking failure in IPA-SRA
[gcc.git] / gcc / lra-constraints.c
index 580da9c3ed668cf3b81a73a3cd122486dda89993..80ca1e06e3108f8a90ecbbac95456a3435a31b37 100644 (file)
@@ -236,12 +236,17 @@ get_reg_class (int regno)
    CL.  Use elimination first if REG is a hard register.  If REG is a
    reload pseudo created by this constraints pass, assume that it will
    be allocated a hard register from its allocno class, but allow that
-   class to be narrowed to CL if it is currently a superset of CL.
+   class to be narrowed to CL if it is currently a superset of CL and
+   if either:
+
+   - ALLOW_ALL_RELOAD_CLASS_CHANGES_P is true or
+   - the instruction we're processing is not a reload move.
 
    If NEW_CLASS is nonnull, set *NEW_CLASS to the new allocno class of
    REGNO (reg), or NO_REGS if no change in its class was needed.  */
 static bool
-in_class_p (rtx reg, enum reg_class cl, enum reg_class *new_class)
+in_class_p (rtx reg, enum reg_class cl, enum reg_class *new_class,
+           bool allow_all_reload_class_changes_p = false)
 {
   enum reg_class rclass, common_class;
   machine_mode reg_mode;
@@ -266,7 +271,8 @@ in_class_p (rtx reg, enum reg_class cl, enum reg_class *new_class)
         typically moves that have many alternatives, and restricting
         reload pseudos for one alternative may lead to situations
         where other reload pseudos are no longer allocatable.  */
-      || (INSN_UID (curr_insn) >= new_insn_uid_start
+      || (!allow_all_reload_class_changes_p
+         && INSN_UID (curr_insn) >= new_insn_uid_start
          && curr_insn_set != NULL
          && ((OBJECT_P (SET_SRC (curr_insn_set))
               && ! CONSTANT_P (SET_SRC (curr_insn_set)))
@@ -400,8 +406,10 @@ valid_address_p (rtx op, struct address_info *ad,
   address_eliminator eliminator (ad);
 
   /* Allow a memory OP if it matches CONSTRAINT, even if CONSTRAINT is more
-     forgiving than "m".  */
-  if (MEM_P (op)
+     forgiving than "m".
+     Need to extract memory from op for special memory constraint,
+     i.e. bcst_mem_operand in i386 backend.  */
+  if (MEM_P (extract_mem_from_operand (op))
       && (insn_extra_memory_constraint (constraint)
          || insn_extra_special_memory_constraint (constraint))
       && constraint_satisfied_p (op, constraint))
@@ -410,14 +418,34 @@ valid_address_p (rtx op, struct address_info *ad,
   return valid_address_p (ad->mode, *ad->outer, ad->as);
 }
 
+/* For special_memory_operand, it could be false for MEM_P (op),
+   i.e. bcst_mem_operand in i386 backend.
+   Extract and return real memory operand or op.  */
+rtx
+extract_mem_from_operand (rtx op)
+{
+  for (rtx x = op;; x = XEXP (x, 0))
+    {
+      if (MEM_P (x))
+       return x;
+      if (GET_RTX_LENGTH (GET_CODE (x)) != 1
+         || GET_RTX_FORMAT (GET_CODE (x))[0] != 'e')
+       break;
+    }
+  return op;
+}
+
 /* Return true if the eliminated form of memory reference OP satisfies
    extra (special) memory constraint CONSTRAINT.  */
 static bool
 satisfies_memory_constraint_p (rtx op, enum constraint_num constraint)
 {
   struct address_info ad;
+  rtx mem = extract_mem_from_operand (op);
+  if (!MEM_P (mem))
+    return false;
 
-  decompose_mem_address (&ad, op);
+  decompose_mem_address (&ad, mem);
   address_eliminator eliminator (&ad);
   return constraint_satisfied_p (op, constraint);
 }
@@ -598,13 +626,12 @@ canonicalize_reload_addr (rtx addr)
   return addr;
 }
 
-/* Create a new pseudo using MODE, RCLASS, ORIGINAL or reuse already
-   created input reload pseudo (only if TYPE is not OP_OUT).  Don't
-   reuse pseudo if IN_SUBREG_P is true and the reused pseudo should be
-   wrapped up in SUBREG.  The result pseudo is returned through
-   RESULT_REG.  Return TRUE if we created a new pseudo, FALSE if we
-   reused the already created input reload pseudo.  Use TITLE to
-   describe new registers for debug purposes.  */
+/* Create a new pseudo using MODE, RCLASS, ORIGINAL or reuse an existing
+   reload pseudo.  Don't reuse an existing reload pseudo if IN_SUBREG_P
+   is true and the reused pseudo should be wrapped up in a SUBREG.
+   The result pseudo is returned through RESULT_REG.  Return TRUE if we
+   created a new pseudo, FALSE if we reused an existing reload pseudo.
+   Use TITLE to describe new registers for debug purposes.  */
 static bool
 get_reload_reg (enum op_type type, machine_mode mode, rtx original,
                enum reg_class rclass, bool in_subreg_p,
@@ -616,6 +643,35 @@ get_reload_reg (enum op_type type, machine_mode mode, rtx original,
 
   if (type == OP_OUT)
     {
+      /* Output reload registers tend to start out with a conservative
+        choice of register class.  Usually this is ALL_REGS, although
+        a target might narrow it (for performance reasons) through
+        targetm.preferred_reload_class.  It's therefore quite common
+        for a reload instruction to require a more restrictive class
+        than the class that was originally assigned to the reload register.
+
+        In these situations, it's more efficient to refine the choice
+        of register class rather than create a second reload register.
+        This also helps to avoid cycling for registers that are only
+        used by reload instructions.  */
+      if (REG_P (original)
+         && (int) REGNO (original) >= new_regno_start
+         && INSN_UID (curr_insn) >= new_insn_uid_start
+         && in_class_p (original, rclass, &new_class, true))
+       {
+         unsigned int regno = REGNO (original);
+         if (lra_dump_file != NULL)
+           {
+             fprintf (lra_dump_file, "  Reuse r%d for output ", regno);
+             dump_value_slim (lra_dump_file, original, 1);
+           }
+         if (new_class != lra_get_allocno_class (regno))
+           lra_change_class (regno, new_class, ", change to", false);
+         if (lra_dump_file != NULL)
+           fprintf (lra_dump_file, "\n");
+         *result_reg = original;
+         return false;
+       }
       *result_reg
        = lra_create_new_reg_with_unique_value (mode, original, rclass, title);
       return true;
@@ -1098,8 +1154,13 @@ match_reload (signed char out, signed char *ins, signed char *outs,
   narrow_reload_pseudo_class (out_rtx, goal_class);
   if (find_reg_note (curr_insn, REG_UNUSED, out_rtx) == NULL_RTX)
     {
+      reg = SUBREG_P (out_rtx) ? SUBREG_REG (out_rtx) : out_rtx;
       start_sequence ();
-      if (out >= 0 && curr_static_id->operand[out].strict_low)
+      /* If we had strict_low_part, use it also in reload to keep other
+        parts unchanged but do it only for regs as strict_low_part
+        has no sense for memory and probably there is no insn pattern
+        to match the reload insn in memory case.  */
+      if (out >= 0 && curr_static_id->operand[out].strict_low && REG_P (reg))
        out_rtx = gen_rtx_STRICT_LOW_PART (VOIDmode, out_rtx);
       lra_emit_move (out_rtx, copy_rtx (new_out_reg));
       emit_insn (*after);
@@ -2409,8 +2470,7 @@ process_alt_operands (int only_alternative)
                      break;
 
                    case CT_SPECIAL_MEMORY:
-                     if (MEM_P (op)
-                         && satisfies_memory_constraint_p (op, cn))
+                     if (satisfies_memory_constraint_p (op, cn))
                        win = true;
                      else if (spilled_pseudo_p (op))
                        win = true;
@@ -2448,7 +2508,7 @@ process_alt_operands (int only_alternative)
          while ((p += len), c);
 
          scratch_p = (operand_reg[nop] != NULL_RTX
-                      && lra_former_scratch_p (REGNO (operand_reg[nop])));
+                      && ira_former_scratch_p (REGNO (operand_reg[nop])));
          /* Record which operands fit this alternative.  */
          if (win)
            {
@@ -3370,13 +3430,14 @@ process_address_1 (int nop, bool check_only_p,
   rtx new_reg;
   HOST_WIDE_INT scale;
   rtx op = *curr_id->operand_loc[nop];
+  rtx mem = extract_mem_from_operand (op);
   const char *constraint = curr_static_id->operand[nop].constraint;
   enum constraint_num cn = lookup_constraint (constraint);
   bool change_p = false;
 
-  if (MEM_P (op)
-      && GET_MODE (op) == BLKmode
-      && GET_CODE (XEXP (op, 0)) == SCRATCH)
+  if (MEM_P (mem)
+      && GET_MODE (mem) == BLKmode
+      && GET_CODE (XEXP (mem, 0)) == SCRATCH)
     return false;
 
   if (insn_extra_address_constraint (cn)
@@ -3389,12 +3450,14 @@ process_address_1 (int nop, bool check_only_p,
       && curr_static_id->operand[nop].is_address)
     decompose_lea_address (&ad, curr_id->operand_loc[nop]);
   /* Do not attempt to decompose arbitrary addresses generated by combine
-     for asm operands with loose constraints, e.g 'X'.  */
-  else if (MEM_P (op)
+     for asm operands with loose constraints, e.g 'X'.
+     Need to extract memory from op for special memory constraint,
+     i.e. bcst_mem_operand in i386 backend.  */
+  else if (MEM_P (mem)
           && !(INSN_CODE (curr_insn) < 0
                && get_constraint_type (cn) == CT_FIXED_FORM
                && constraint_satisfied_p (op, cn)))
-    decompose_mem_address (&ad, op);
+    decompose_mem_address (&ad, mem);
   else if (GET_CODE (op) == SUBREG
           && MEM_P (SUBREG_REG (op)))
     decompose_mem_address (&ad, SUBREG_REG (op));
@@ -3891,10 +3954,10 @@ curr_insn_transform (bool check_only_p)
   no_input_reloads_p = no_output_reloads_p = false;
   goal_alt_number = -1;
   change_p = sec_mem_p = false;
-  /* JUMP_INSNs and CALL_INSNs are not allowed to have any output
-     reloads; neither are insns that SET cc0.  Insns that use CC0 are
-     not allowed to have any input reloads.  */
-  if (JUMP_P (curr_insn) || CALL_P (curr_insn))
+  /* CALL_INSNs are not allowed to have any output reloads; neither
+     are insns that SET cc0.  Insns that use CC0 are not allowed to
+     have any input reloads.  */
+  if (CALL_P (curr_insn))
     no_output_reloads_p = true;
 
   if (HAVE_cc0 && reg_referenced_p (cc0_rtx, PATTERN (curr_insn)))
@@ -4041,9 +4104,18 @@ curr_insn_transform (bool check_only_p)
       error_for_asm (curr_insn,
                     "inconsistent operand constraints in an %<asm%>");
       lra_asm_error_p = true;
-      /* Avoid further trouble with this insn.  Don't generate use
-        pattern here as we could use the insn SP offset.  */
-      lra_set_insn_deleted (curr_insn);
+      if (! JUMP_P (curr_insn))
+       {
+         /* Avoid further trouble with this insn.  Don't generate use
+            pattern here as we could use the insn SP offset.  */
+         lra_set_insn_deleted (curr_insn);
+       }
+      else
+       {
+         lra_invalidate_insn_data (curr_insn);
+         ira_nullify_asm_goto (curr_insn);
+         lra_update_insn_regno_info (curr_insn);
+       }
       return true;
     }
 
@@ -4297,8 +4369,8 @@ curr_insn_transform (bool check_only_p)
                 assigment pass and the scratch pseudo will be
                 spilled.  Spilled scratch pseudos are transformed
                 back to scratches at the LRA end.  */
-             && lra_former_scratch_operand_p (curr_insn, i)
-             && lra_former_scratch_p (REGNO (op)))
+             && ira_former_scratch_operand_p (curr_insn, i)
+             && ira_former_scratch_p (REGNO (op)))
            {
              int regno = REGNO (op);
              lra_change_class (regno, NO_REGS, "      Change to", true);
@@ -4319,7 +4391,7 @@ curr_insn_transform (bool check_only_p)
              && goal_alt[i] != NO_REGS && REG_P (op)
              && (regno = REGNO (op)) >= FIRST_PSEUDO_REGISTER
              && regno < new_regno_start
-             && ! lra_former_scratch_p (regno)
+             && ! ira_former_scratch_p (regno)
              && reg_renumber[regno] < 0
              /* Check that the optional reload pseudo will be able to
                 hold given mode value.  */
@@ -4742,12 +4814,12 @@ multi_block_pseudo_p (int regno)
   if (regno < FIRST_PSEUDO_REGISTER)
     return false;
 
-    EXECUTE_IF_SET_IN_BITMAP (&lra_reg_info[regno].insn_bitmap, 0, uid, bi)
-      if (bb == NULL)
-       bb = BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn);
-      else if (BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn) != bb)
-       return true;
-    return false;
+  EXECUTE_IF_SET_IN_BITMAP (&lra_reg_info[regno].insn_bitmap, 0, uid, bi)
+    if (bb == NULL)
+      bb = BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn);
+    else if (BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn) != bb)
+      return true;
+  return false;
 }
 
 /* Return true if LIST contains a deleted insn.  */