]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR middle-end/32004 (can't find a register in class 'GENERAL_REGS' while reloading...
authorPaolo Bonzini <bonzini@gnu.org>
Fri, 6 Jul 2007 15:12:55 +0000 (15:12 +0000)
committerPaolo Bonzini <bonzini@gcc.gnu.org>
Fri, 6 Jul 2007 15:12:55 +0000 (15:12 +0000)
2007-07-06  Paolo Bonzini  <bonzini@gnu.org>

PR middle-end/32004
* function.c (match_asm_constraints_1, rest_of_match_asm_constraints,
pass_match_asm_constraints): New.
* passes.c (init_optimization_passes): Add new pass.
* stmt.c (expand_asm_operands): Set cfun->has_asm_statement.
* function.h (struct function): Add has_asm_statement bit.
(current_function_has_asm_statement): New.
* tree-pass.h (pass_match_asm_constraints): New.

From-SVN: r126419

gcc/ChangeLog
gcc/function.c
gcc/function.h
gcc/passes.c
gcc/stmt.c
gcc/testsuite/gcc.target/i386/pr21291.c
gcc/tree-pass.h

index ea8b3338450f17eb36714abae3e226f4af66ca13..757f84f7c447ea38b473d5715cd48640788e8261 100644 (file)
@@ -1,3 +1,14 @@
+2007-07-06  Paolo Bonzini  <bonzini@gnu.org>
+
+       PR middle-end/32004
+       * function.c (match_asm_constraints_1, rest_of_match_asm_constraints,
+       pass_match_asm_constraints): New.
+       * passes.c (init_optimization_passes): Add new pass.
+       * stmt.c (expand_asm_operands): Set cfun->has_asm_statement.
+       * function.h (struct function): Add has_asm_statement bit.
+       (current_function_has_asm_statement): New.
+       * tree-pass.h (pass_match_asm_constraints): New.
+
 2007-07-06  Uros Bizjak  <ubizjak@gmail.com>
 
        PR rtl-optimization/32450
index 46408da0b21f6ab2096cd4c0e067d51a4b659cf6..9912fa9c0a15a36f6f94e1e1497e9afab857f0aa 100644 (file)
@@ -5597,6 +5597,137 @@ struct tree_opt_pass pass_leaf_regs =
   0,                                    /* todo_flags_finish */
   0                                     /* letter */
 };
+\f
+
+/* This mini-pass fixes fall-out from SSA in asm statements that have
+   in-out constraints.  Say you start with 
+
+     orig = inout;
+     asm ("": "+mr" (inout));
+     use (orig);
+
+   which is transformed very early to use explicit output and match operands:
+
+     orig = inout;
+     asm ("": "=mr" (inout) : "0" (inout));
+     use (orig);
+
+   Or, after SSA and copyprop,
+
+     asm ("": "=mr" (inout_2) : "0" (inout_1));
+     use (inout_1);
+
+   Clearly inout_2 and inout_1 can't be coalesced easily anymore, as
+   they represent two separate values, so they will get different pseudo
+   registers during expansion.  Then, since the two operands need to match
+   per the constraints, but use different pseudo registers, reload can
+   only register a reload for these operands.  But reloads can only be
+   satisfied by hardregs, not by memory, so we need a register for this
+   reload, just because we are presented with non-matching operands.
+   So, even though we allow memory for this operand, no memory can be
+   used for it, just because the two operands don't match.  This can
+   cause reload failures on register-starved targets.
+
+   So it's a symptom of reload not being able to use memory for reloads
+   or, alternatively it's also a symptom of both operands not coming into
+   reload as matching (in which case the pseudo could go to memory just
+   fine, as the alternative allows it, and no reload would be necessary).
+   We fix the latter problem here, by transforming
+
+     asm ("": "=mr" (inout_2) : "0" (inout_1));
+
+   back to
+
+     inout_2 = inout_1;
+     asm ("": "=mr" (inout_2) : "0" (inout_2));  */
+
+static void
+match_asm_constraints_1 (rtx insn, rtx *p_sets, int noutputs)
+{
+  int i;
+  rtx op = SET_SRC (p_sets[0]);
+  int ninputs = ASM_OPERANDS_INPUT_LENGTH (op);
+  rtvec inputs = ASM_OPERANDS_INPUT_VEC (op);
+
+  for (i = 0; i < ninputs; i++)
+    {
+      rtx input, output, insns;
+      const char *constraint = ASM_OPERANDS_INPUT_CONSTRAINT (op, i);
+      char *end;
+      int match;
+
+      match = strtoul (constraint, &end, 10);
+      if (end == constraint)
+       continue;
+
+      gcc_assert (match < noutputs);
+      output = SET_DEST (p_sets[match]);
+      input = RTVEC_ELT (inputs, i);
+      if (rtx_equal_p (output, input)
+         || (GET_MODE (input) != VOIDmode
+             && GET_MODE (input) != GET_MODE (output)))
+       continue;
+
+      start_sequence ();
+      emit_move_insn (copy_rtx (output), input);
+      RTVEC_ELT (inputs, i) = copy_rtx (output);
+      insns = get_insns ();
+      end_sequence ();
+
+      emit_insn_before (insns, insn);
+    }
+}
+
+static void
+rest_of_match_asm_constraints (void)
+{
+  basic_block bb;
+  rtx insn, pat, *p_sets;
+  int noutputs;
+
+  if (!cfun->has_asm_statement)
+    return;
+
+  FOR_EACH_BB (bb)
+    {
+      FOR_BB_INSNS (bb, insn)
+       {
+         if (!INSN_P (insn))
+           continue;
 
+         pat = PATTERN (insn);
+         if (GET_CODE (pat) == PARALLEL)
+           p_sets = &XVECEXP (pat, 0, 0), noutputs = XVECLEN (pat, 0);
+         else if (GET_CODE (pat) == SET)
+           p_sets = &PATTERN (insn), noutputs = 1;
+         else
+           continue;
+
+         if (GET_CODE (*p_sets) == SET
+             && GET_CODE (SET_SRC (*p_sets)) == ASM_OPERANDS)
+           match_asm_constraints_1 (insn, p_sets, noutputs);
+        }
+    }
+
+  update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
+                                    PROP_DEATH_NOTES);
+}
+
+struct tree_opt_pass pass_match_asm_constraints =
+{
+  "asmcons",                           /* name */
+  NULL,                                        /* gate */
+  rest_of_match_asm_constraints,       /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  0,                                   /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  0                                     /* letter */
+};
 
 #include "gt-function.h"
index c1482ac328e659d59871ab2a8528bc489066ab22..705284ac6a7deddb1c9578e07eb0c8054173c5f6 100644 (file)
@@ -408,6 +408,9 @@ struct function GTY(())
   /* Nonzero if function being compiled has nonlocal gotos to parent
      function.  */
   unsigned int has_nonlocal_goto : 1;
+  
+  /* Nonzero if function being compiled has an asm statement.  */
+  unsigned int has_asm_statement : 1;
 
   /* Nonzero if the current function is a thunk, i.e., a lightweight
      function implemented by the output_mi_thunk hook) that just
@@ -506,6 +509,7 @@ extern int trampolines_created;
 #define current_function_epilogue_delay_list (cfun->epilogue_delay_list)
 #define current_function_has_nonlocal_label (cfun->has_nonlocal_label)
 #define current_function_has_nonlocal_goto (cfun->has_nonlocal_goto)
+#define current_function_has_asm_statement (cfun->has_asm_statement)
 
 #define return_label (cfun->x_return_label)
 #define naked_return_label (cfun->x_naked_return_label)
index 8a844a890f70bb2f255b90e40fc4318b31d39740..51ea9c93a4b99f81bf816417e936ebcaab969111 100644 (file)
@@ -639,6 +639,7 @@ init_optimization_passes (void)
   NEXT_PASS (pass_split_all_insns);
   NEXT_PASS (pass_mode_switching);
   NEXT_PASS (pass_recompute_reg_usage);
+  NEXT_PASS (pass_match_asm_constraints);
   NEXT_PASS (pass_sms);
   NEXT_PASS (pass_sched);
   NEXT_PASS (pass_local_alloc);
index e08eab051f98bcfd32b202c09841dfe01db99147..7201a9a899e3319be7603b6362a9e7dc5f144b67 100644 (file)
@@ -1079,6 +1079,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
     if (real_output_rtx[i])
       emit_move_insn (real_output_rtx[i], output_rtx[i]);
 
+  cfun->has_asm_statement = 1;
   free_temp_slots ();
 }
 
index acfc43df67f94b0f1e3e8ed0516af85929dae3ee..b597509854b26f6994add789d4090b0afcf28354 100644 (file)
@@ -1,3 +1,8 @@
+/* The asm has 2 "r" in/out operands, 1 earlyclobber "r" output, 1 "r"
+   input and 2 fixed "r" clobbers (eax and edx), so there are a total of
+   6 registers that must not conflict.  Add to that the PIC register,
+   the frame pointer, and the stack pointer, and we've run out of
+   registers on 32-bit targets.  */
 /* { dg-do compile } */
 /* { dg-options "-O" } */
 
index 1f45ffd57192d659423e74e9612a9fc2ecfcccd2..97bfac675f5c7093b7547dec6b77bab46adc1370 100644 (file)
@@ -335,7 +335,7 @@ extern struct tree_opt_pass pass_life;
 extern struct tree_opt_pass pass_combine;
 extern struct tree_opt_pass pass_if_after_combine;
 extern struct tree_opt_pass pass_partition_blocks;
-extern struct tree_opt_pass pass_partition_blocks;
+extern struct tree_opt_pass pass_match_asm_constraints;
 extern struct tree_opt_pass pass_regmove;
 extern struct tree_opt_pass pass_split_all_insns;
 extern struct tree_opt_pass pass_mode_switching;