OSDN Git Service

PR target/48220
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 15 Jul 2011 17:09:56 +0000 (17:09 +0000)
committerebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 15 Jul 2011 17:09:56 +0000 (17:09 +0000)
* doc/md.texi (Standard Names): Document window_save.
* cfgexpand.c (expand_debug_parm_decl): New function extracted from
expand_debug_expr and expand_debug_source_expr.  If the target has
a window_save instruction, adjust the ENTRY_VALUE_EXP.
(expand_debug_expr) <SSA_NAME>: Call expand_debug_parm_decl if the
SSA_NAME_VAR is a parameter.
(expand_debug_source_expr) <PARM_DECL>: Call expand_debug_parm_decl.
* var-tracking.c (parm_reg_t): New type and associated vector type.
(windowed_parm_regs): New variable.
(adjust_insn): If the target has a window_save instruction and this
is the instruction, make its effect on parameter registers explicit.
(next_non_note_insn_var_location): New function.
(emit_notes_in_bb): Use it instead of NEXT_INSN throughout.
(vt_add_function_parameter): If the target has a window_save insn,
adjust the incoming RTL and record that in windowed_parm_regs.
(vt_finalize): Free windowed_parm_regs.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@176318 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cfgexpand.c
gcc/doc/md.texi
gcc/var-tracking.c

index f321c8d..fdcb498 100644 (file)
@@ -1,3 +1,23 @@
+2011-07-15  Eric Botcazou  <ebotcazou@adacore.com>
+
+       PR target/48220
+       * doc/md.texi (Standard Names): Document window_save.
+       * cfgexpand.c (expand_debug_parm_decl): New function extracted from
+       expand_debug_expr and expand_debug_source_expr.  If the target has
+       a window_save instruction, adjust the ENTRY_VALUE_EXP.
+       (expand_debug_expr) <SSA_NAME>: Call expand_debug_parm_decl if the
+       SSA_NAME_VAR is a parameter.
+       (expand_debug_source_expr) <PARM_DECL>: Call expand_debug_parm_decl.
+       * var-tracking.c (parm_reg_t): New type and associated vector type.
+       (windowed_parm_regs): New variable.
+       (adjust_insn): If the target has a window_save instruction and this
+       is the instruction, make its effect on parameter registers explicit.
+       (next_non_note_insn_var_location): New function.
+       (emit_notes_in_bb): Use it instead of NEXT_INSN throughout.
+       (vt_add_function_parameter): If the target has a window_save insn,
+       adjust the incoming RTL and record that in windowed_parm_regs.
+       (vt_finalize): Free windowed_parm_regs.
+
 2011-07-15  Bernd Schmidt  <bernds@codesourcery.com>
 
        * doc/invoke.texi (C6X Options): New section.
index 60e5752..f87308c 100644 (file)
@@ -2358,8 +2358,60 @@ convert_debug_memory_address (enum machine_mode mode, rtx x,
   return x;
 }
 
-/* Return an RTX equivalent to the value of the tree expression
-   EXP.  */
+/* Return an RTX equivalent to the value of the parameter DECL.  */
+
+static rtx
+expand_debug_parm_decl (tree decl)
+{
+  rtx incoming = DECL_INCOMING_RTL (decl);
+
+  if (incoming
+      && GET_MODE (incoming) != BLKmode
+      && ((REG_P (incoming) && HARD_REGISTER_P (incoming))
+         || (MEM_P (incoming)
+             && REG_P (XEXP (incoming, 0))
+             && HARD_REGISTER_P (XEXP (incoming, 0)))))
+    {
+      rtx rtl = gen_rtx_ENTRY_VALUE (GET_MODE (incoming));
+
+#ifdef HAVE_window_save
+      /* DECL_INCOMING_RTL uses the INCOMING_REGNO of parameter registers.
+        If the target machine has an explicit window save instruction, the
+        actual entry value is the corresponding OUTGOING_REGNO instead.  */
+      if (REG_P (incoming)
+         && OUTGOING_REGNO (REGNO (incoming)) != REGNO (incoming))
+       incoming
+         = gen_rtx_REG_offset (incoming, GET_MODE (incoming),
+                               OUTGOING_REGNO (REGNO (incoming)), 0);
+      else if (MEM_P (incoming))
+       {
+         rtx reg = XEXP (incoming, 0);
+         if (OUTGOING_REGNO (REGNO (reg)) != REGNO (reg))
+           {
+             reg = gen_raw_REG (GET_MODE (reg), OUTGOING_REGNO (REGNO (reg)));
+             incoming = replace_equiv_address_nv (incoming, reg);
+           }
+       }
+#endif
+
+      ENTRY_VALUE_EXP (rtl) = incoming;
+      return rtl;
+    }
+
+  if (incoming
+      && GET_MODE (incoming) != BLKmode
+      && !TREE_ADDRESSABLE (decl)
+      && MEM_P (incoming)
+      && (XEXP (incoming, 0) == virtual_incoming_args_rtx
+         || (GET_CODE (XEXP (incoming, 0)) == PLUS
+             && XEXP (XEXP (incoming, 0), 0) == virtual_incoming_args_rtx
+             && CONST_INT_P (XEXP (XEXP (incoming, 0), 1)))))
+    return incoming;
+
+  return NULL_RTX;
+}
+
+/* Return an RTX equivalent to the value of the tree expression EXP.  */
 
 static rtx
 expand_debug_expr (tree exp)
@@ -3169,36 +3221,12 @@ expand_debug_expr (tree exp)
                if (SSA_NAME_IS_DEFAULT_DEF (exp)
                    && TREE_CODE (SSA_NAME_VAR (exp)) == PARM_DECL)
                  {
-                   rtx incoming = DECL_INCOMING_RTL (SSA_NAME_VAR (exp));
-                   if (incoming
-                       && GET_MODE (incoming) != BLKmode
-                       && ((REG_P (incoming) && HARD_REGISTER_P (incoming))
-                           || (MEM_P (incoming)
-                               && REG_P (XEXP (incoming, 0))
-                               && HARD_REGISTER_P (XEXP (incoming, 0)))))
-                     {
-                       op0 = gen_rtx_ENTRY_VALUE (GET_MODE (incoming));
-                       ENTRY_VALUE_EXP (op0) = incoming;
-                       goto adjust_mode;
-                     }
-                   if (incoming
-                       && MEM_P (incoming)
-                       && !TREE_ADDRESSABLE (SSA_NAME_VAR (exp))
-                       && GET_MODE (incoming) != BLKmode
-                       && (XEXP (incoming, 0) == virtual_incoming_args_rtx
-                           || (GET_CODE (XEXP (incoming, 0)) == PLUS
-                               && XEXP (XEXP (incoming, 0), 0)
-                                  == virtual_incoming_args_rtx
-                               && CONST_INT_P (XEXP (XEXP (incoming, 0),
-                                                     1)))))
-                     {
-                       op0 = incoming;
-                       goto adjust_mode;
-                     }
+                   op0 = expand_debug_parm_decl (SSA_NAME_VAR (exp));
+                   if (op0)
+                     goto adjust_mode;
                    op0 = expand_debug_expr (SSA_NAME_VAR (exp));
-                   if (!op0)
-                     return NULL;
-                   goto adjust_mode;
+                   if (op0)
+                     goto adjust_mode;
                  }
                return NULL;
              }
@@ -3327,36 +3355,14 @@ expand_debug_source_expr (tree exp)
     {
     case PARM_DECL:
       {
-       rtx incoming = DECL_INCOMING_RTL (exp);
        mode = DECL_MODE (exp);
-       if (incoming
-           && GET_MODE (incoming) != BLKmode
-           && ((REG_P (incoming) && HARD_REGISTER_P (incoming))
-               || (MEM_P (incoming)
-                   && REG_P (XEXP (incoming, 0))
-                   && HARD_REGISTER_P (XEXP (incoming, 0)))))
-         {
-           op0 = gen_rtx_ENTRY_VALUE (GET_MODE (incoming));
-           ENTRY_VALUE_EXP (op0) = incoming;
-           break;
-         }
-       if (incoming
-           && MEM_P (incoming)
-           && !TREE_ADDRESSABLE (exp)
-           && GET_MODE (incoming) != BLKmode
-           && (XEXP (incoming, 0) == virtual_incoming_args_rtx
-               || (GET_CODE (XEXP (incoming, 0)) == PLUS
-                   && XEXP (XEXP (incoming, 0), 0)
-                      == virtual_incoming_args_rtx
-                   && CONST_INT_P (XEXP (XEXP (incoming, 0), 1)))))
-         {
-           op0 = incoming;
-           break;
-         }
+       op0 = expand_debug_parm_decl (exp);
+       if (op0)
+          break;
        /* See if this isn't an argument that has been completely
           optimized out.  */
        if (!DECL_RTL_SET_P (exp)
-           && incoming == NULL_RTX
+           && !DECL_INCOMING_RTL (exp)
            && DECL_ABSTRACT_ORIGIN (current_function_decl))
          {
            tree aexp = exp;
index 23047ca..1f08dae 100644 (file)
@@ -5333,6 +5333,14 @@ Using a prologue pattern is generally preferred over defining
 The @code{prologue} pattern is particularly useful for targets which perform
 instruction scheduling.
 
+@cindex @code{window_save} instruction pattern
+@anchor{window_save instruction pattern}
+@item @samp{window_save}
+This pattern, if defined, emits RTL for a register window save.  It should
+be defined if the target machine has register windows but the window events
+are decoupled from calls to subroutines.  The canonical example is the SPARC
+architecture.
+
 @cindex @code{epilogue} instruction pattern
 @anchor{epilogue instruction pattern}
 @item @samp{epilogue}
index b3f84a1..4842b78 100644 (file)
@@ -34,7 +34,7 @@
    operations.
    The micro operations of one instruction are ordered so that
    pre-modifying stack adjustment < use < use with no var < call insn <
-     < set < clobber < post-modifying stack adjustment
+     < clobber < set < post-modifying stack adjustment
 
    Then, a forward dataflow analysis is performed to find out how locations
    of variables change through code and to propagate the variable locations
@@ -400,6 +400,17 @@ static shared_hash empty_shared_hash;
 /* Scratch register bitmap used by cselib_expand_value_rtx.  */
 static bitmap scratch_regs = NULL;
 
+typedef struct GTY(()) parm_reg {
+  rtx outgoing;
+  rtx incoming;
+} parm_reg_t;
+
+DEF_VEC_O(parm_reg_t);
+DEF_VEC_ALLOC_O(parm_reg_t, gc);
+
+/* Vector of windowed parameter registers, if any.  */
+static VEC(parm_reg_t, gc) *windowed_parm_regs = NULL;
+
 /* Variable used to tell whether cselib_process_insn called our hook.  */
 static bool cselib_hook_called;
 
@@ -970,6 +981,33 @@ adjust_insn (basic_block bb, rtx insn)
 {
   struct adjust_mem_data amd;
   rtx set;
+
+#ifdef HAVE_window_save
+  /* If the target machine has an explicit window save instruction, the
+     transformation OUTGOING_REGNO -> INCOMING_REGNO is done there.  */
+  if (RTX_FRAME_RELATED_P (insn)
+      && find_reg_note (insn, REG_CFA_WINDOW_SAVE, NULL_RTX))
+    {
+      unsigned int i, nregs = VEC_length(parm_reg_t, windowed_parm_regs);
+      rtx rtl = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs * 2));
+      parm_reg_t *p;
+
+      FOR_EACH_VEC_ELT (parm_reg_t, windowed_parm_regs, i, p)
+       {
+         XVECEXP (rtl, 0, i * 2)
+           = gen_rtx_SET (VOIDmode, p->incoming, p->outgoing);
+         /* Do not clobber the attached DECL, but only the REG.  */
+         XVECEXP (rtl, 0, i * 2 + 1)
+           = gen_rtx_CLOBBER (GET_MODE (p->outgoing),
+                              gen_raw_REG (GET_MODE (p->outgoing),
+                                           REGNO (p->outgoing)));
+       }
+
+      validate_change (NULL_RTX, &PATTERN (insn), rtl, true);
+      return;
+    }
+#endif
+
   amd.mem_mode = VOIDmode;
   amd.stack_adjust = -VTI (bb)->out.stack_adjust;
   amd.side_effects = NULL_RTX;
@@ -8002,6 +8040,23 @@ emit_notes_for_differences (rtx insn, dataflow_set *old_set,
   emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN, new_set->vars);
 }
 
+/* Return the next insn after INSN that is not a NOTE_INSN_VAR_LOCATION.  */
+
+static rtx
+next_non_note_insn_var_location (rtx insn)
+{
+  while (insn)
+    {
+      insn = NEXT_INSN (insn);
+      if (insn == 0
+         || !NOTE_P (insn)
+         || NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION)
+       break;
+    }
+
+  return insn;
+}
+
 /* Emit the notes for changes of location parts in the basic block BB.  */
 
 static void
@@ -8016,6 +8071,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
   FOR_EACH_VEC_ELT (micro_operation, VTI (bb)->mos, i, mo)
     {
       rtx insn = mo->insn;
+      rtx next_insn = next_non_note_insn_var_location (insn);
 
       switch (mo->type)
        {
@@ -8222,7 +8278,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
                val_store (set, XEXP (reverse, 0), XEXP (reverse, 1),
                           insn, false);
 
-             emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN,
+             emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
                                      set->vars);
            }
            break;
@@ -8245,7 +8301,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
                var_mem_delete_and_set (set, loc, true, VAR_INIT_STATUS_INITIALIZED,
                                        set_src);
 
-             emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN,
+             emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
                                      set->vars);
            }
            break;
@@ -8270,7 +8326,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
              else
                var_mem_delete_and_set (set, loc, false, src_status, set_src);
 
-             emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN,
+             emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
                                      set->vars);
            }
            break;
@@ -8297,7 +8353,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
              else
                var_mem_delete (set, loc, true);
 
-             emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN,
+             emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
                                      set->vars);
            }
            break;
@@ -8483,6 +8539,39 @@ vt_add_function_parameter (tree parm)
                                    plus_constant (arg_pointer_rtx, off));
     }
 
+#ifdef HAVE_window_save
+  /* DECL_INCOMING_RTL uses the INCOMING_REGNO of parameter registers.
+     If the target machine has an explicit window save instruction, the
+     actual entry value is the corresponding OUTGOING_REGNO instead.  */
+  if (REG_P (incoming)
+      && HARD_REGISTER_P (incoming)
+      && OUTGOING_REGNO (REGNO (incoming)) != REGNO (incoming))
+    {
+      parm_reg_t *p
+       = VEC_safe_push (parm_reg_t, gc, windowed_parm_regs, NULL);
+      p->incoming = incoming;
+      incoming
+       = gen_rtx_REG_offset (incoming, GET_MODE (incoming),
+                             OUTGOING_REGNO (REGNO (incoming)), 0);
+      p->outgoing = incoming;
+    }
+  else if (MEM_P (incoming)
+          && REG_P (XEXP (incoming, 0))
+          && HARD_REGISTER_P (XEXP (incoming, 0)))
+    {
+      rtx reg = XEXP (incoming, 0);
+      if (OUTGOING_REGNO (REGNO (reg)) != REGNO (reg))
+       {
+         parm_reg_t *p
+           = VEC_safe_push (parm_reg_t, gc, windowed_parm_regs, NULL);
+         p->incoming = reg;
+         reg = gen_raw_REG (GET_MODE (reg), OUTGOING_REGNO (REGNO (reg)));
+         p->outgoing = reg;
+         incoming = replace_equiv_address_nv (incoming, reg);
+       }
+    }
+#endif
+
   if (!vt_get_decl_and_offset (incoming, &decl, &offset))
     {
       if (REG_P (incoming) || MEM_P (incoming))
@@ -9046,6 +9135,7 @@ vt_finalize (void)
       cselib_finish ();
       BITMAP_FREE (scratch_regs);
       scratch_regs = NULL;
+      VEC_free (parm_reg_t, gc, windowed_parm_regs);
     }
 
   if (vui_vec)