OSDN Git Service

dwarf2cfi: Generate remember/restore_state.
[pf3gnuchains/gcc-fork.git] / gcc / cfgexpand.c
index a3abc84..f87308c 100644 (file)
@@ -57,6 +57,8 @@ struct ssaexpand SA;
    of comminucating the profile info to the builtin expanders.  */
 gimple currently_expanding_gimple_stmt;
 
+static rtx expand_debug_expr (tree);
+
 /* Return an expression tree corresponding to the RHS of GIMPLE
    statement STMT.  */
 
@@ -158,11 +160,6 @@ struct stack_var
   /* The Variable.  */
   tree decl;
 
-  /* The offset of the variable.  During partitioning, this is the
-     offset relative to the partition.  After partitioning, this
-     is relative to the stack frame.  */
-  HOST_WIDE_INT offset;
-
   /* Initially, the size of the variable.  Later, the size of the partition,
      if this variable becomes it's partition's representative.  */
   HOST_WIDE_INT size;
@@ -268,7 +265,6 @@ add_stack_var (tree decl)
   v = &stack_vars[stack_vars_num];
 
   v->decl = decl;
-  v->offset = 0;
   v->size = tree_low_cst (DECL_SIZE_UNIT (SSAVAR (decl)), 1);
   /* Ensure that all variables have size, so that &a != &b for any two
      variables that are simultaneously live.  */
@@ -373,8 +369,9 @@ add_alias_set_conflicts (void)
                 to elements will conflict.  In case of unions we have
                 to be careful as type based aliasing rules may say
                 access to the same memory does not conflict.  So play
-                safe and add a conflict in this case.  */
-             || contains_union)
+                safe and add a conflict in this case when
+                 -fstrict-aliasing is used.  */
+              || (contains_union && flag_strict_aliasing))
            add_stack_var_conflict (i, j);
        }
     }
@@ -404,9 +401,9 @@ stack_var_cmp (const void *a, const void *b)
     return (int)largeb - (int)largea;
 
   /* Secondary compare on size, decreasing  */
-  if (sizea < sizeb)
-    return -1;
   if (sizea > sizeb)
+    return -1;
+  if (sizea < sizeb)
     return 1;
 
   /* Tertiary compare on true alignment, decreasing.  */
@@ -565,28 +562,19 @@ update_alias_info_with_stack_vars (void)
 
 /* A subroutine of partition_stack_vars.  The UNION portion of a UNION/FIND
    partitioning algorithm.  Partitions A and B are known to be non-conflicting.
-   Merge them into a single partition A.
-
-   At the same time, add OFFSET to all variables in partition B.  At the end
-   of the partitioning process we've have a nice block easy to lay out within
-   the stack frame.  */
+   Merge them into a single partition A.  */
 
 static void
-union_stack_vars (size_t a, size_t b, HOST_WIDE_INT offset)
+union_stack_vars (size_t a, size_t b)
 {
-  size_t i, last;
   struct stack_var *vb = &stack_vars[b];
   bitmap_iterator bi;
   unsigned u;
 
-  /* Update each element of partition B with the given offset,
-     and merge them into partition A.  */
-  for (last = i = b; i != EOC; last = i, i = stack_vars[i].next)
-    {
-      stack_vars[i].offset += offset;
-      stack_vars[i].representative = a;
-    }
-  stack_vars[last].next = stack_vars[a].next;
+  gcc_assert (stack_vars[b].next == EOC);
+   /* Add B to A's partition.  */
+  stack_vars[b].next = stack_vars[a].next;
+  stack_vars[b].representative = a;
   stack_vars[a].next = b;
 
   /* Update the required alignment of partition A to account for B.  */
@@ -606,16 +594,13 @@ union_stack_vars (size_t a, size_t b, HOST_WIDE_INT offset)
    partitions constrained by the interference graph.  The overall
    algorithm used is as follows:
 
-       Sort the objects by size.
+       Sort the objects by size in descending order.
        For each object A {
          S = size(A)
          O = 0
          loop {
            Look for the largest non-conflicting object B with size <= S.
            UNION (A, B)
-           offset(B) = O
-           O += size(B)
-           S -= size(B)
          }
        }
 */
@@ -637,24 +622,23 @@ partition_stack_vars (void)
   for (si = 0; si < n; ++si)
     {
       size_t i = stack_vars_sorted[si];
-      HOST_WIDE_INT isize = stack_vars[i].size;
       unsigned int ialign = stack_vars[i].alignb;
-      HOST_WIDE_INT offset = 0;
 
-      for (sj = si; sj-- > 0; )
+      /* Ignore objects that aren't partition representatives. If we
+         see a var that is not a partition representative, it must
+         have been merged earlier.  */
+      if (stack_vars[i].representative != i)
+        continue;
+
+      for (sj = si + 1; sj < n; ++sj)
        {
          size_t j = stack_vars_sorted[sj];
-         HOST_WIDE_INT jsize = stack_vars[j].size;
          unsigned int jalign = stack_vars[j].alignb;
 
          /* Ignore objects that aren't partition representatives.  */
          if (stack_vars[j].representative != j)
            continue;
 
-         /* Ignore objects too large for the remaining space.  */
-         if (isize < jsize)
-           continue;
-
          /* Ignore conflicting objects.  */
          if (stack_var_conflict_p (i, j))
            continue;
@@ -665,25 +649,8 @@ partition_stack_vars (void)
              != (jalign * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT))
            continue;
 
-         /* Refine the remaining space check to include alignment.  */
-         if (offset & (jalign - 1))
-           {
-             HOST_WIDE_INT toff = offset;
-             toff += jalign - 1;
-             toff &= -(HOST_WIDE_INT)jalign;
-             if (isize - (toff - offset) < jsize)
-               continue;
-
-             isize -= toff - offset;
-             offset = toff;
-           }
-
          /* UNION the objects, placing J at OFFSET.  */
-         union_stack_vars (i, j, offset);
-
-         isize -= jsize;
-         if (isize == 0)
-           break;
+         union_stack_vars (i, j);
        }
     }
 
@@ -713,9 +680,8 @@ dump_stack_var_partition (void)
        {
          fputc ('\t', dump_file);
          print_generic_expr (dump_file, stack_vars[j].decl, dump_flags);
-         fprintf (dump_file, ", offset " HOST_WIDE_INT_PRINT_DEC "\n",
-                  stack_vars[j].offset);
        }
+      fputc ('\n', dump_file);
     }
 }
 
@@ -864,10 +830,9 @@ expand_stack_vars (bool (*pred) (tree))
         partition.  */
       for (j = i; j != EOC; j = stack_vars[j].next)
        {
-         gcc_assert (stack_vars[j].offset <= stack_vars[i].size);
          expand_one_stack_var_at (stack_vars[j].decl,
                                   base, base_align,
-                                  stack_vars[j].offset + offset);
+                                  offset);
        }
     }
 
@@ -1135,7 +1100,9 @@ expand_used_vars_for_block (tree block, bool toplevel)
 
   /* Expand all variables at this level.  */
   for (t = BLOCK_VARS (block); t ; t = DECL_CHAIN (t))
-    if (TREE_USED (t))
+    if (TREE_USED (t)
+        && ((TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != RESULT_DECL)
+           || !DECL_NONSHAREABLE (t)))
       expand_one_var (t, toplevel, true);
 
   this_sv_num = stack_vars_num;
@@ -1168,6 +1135,8 @@ clear_tree_used (tree block)
 
   for (t = BLOCK_VARS (block); t ; t = DECL_CHAIN (t))
     /* if (!TREE_STATIC (t) && !DECL_EXTERNAL (t)) */
+    if ((TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != RESULT_DECL)
+       || !DECL_NONSHAREABLE (t))
       TREE_USED (t) = 0;
 
   for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t))
@@ -1896,6 +1865,21 @@ expand_call_stmt (gimple stmt)
   SET_EXPR_LOCATION (exp, gimple_location (stmt));
   TREE_BLOCK (exp) = gimple_block (stmt);
 
+  /* Ensure RTL is created for debug args.  */
+  if (decl && DECL_HAS_DEBUG_ARGS_P (decl))
+    {
+      VEC(tree, gc) **debug_args = decl_debug_args_lookup (decl);
+      unsigned int ix;
+      tree dtemp;
+
+      if (debug_args)
+       for (ix = 1; VEC_iterate (tree, *debug_args, ix, dtemp); ix += 2)
+         {
+           gcc_assert (TREE_CODE (dtemp) == DEBUG_EXPR_DECL);
+           expand_debug_expr (dtemp);
+         }
+    }
+
   lhs = gimple_call_lhs (stmt);
   if (lhs)
     expand_assignment (lhs, exp, false);
@@ -2319,7 +2303,7 @@ convert_debug_memory_address (enum machine_mode mode, rtx x,
   if (GET_MODE (x) == mode || GET_MODE (x) == VOIDmode)
     return x;
 
-  if (GET_MODE_BITSIZE (mode) < GET_MODE_BITSIZE (xmode))
+  if (GET_MODE_PRECISION (mode) < GET_MODE_PRECISION (xmode))
     x = simplify_gen_subreg (mode, x, xmode,
                             subreg_lowpart_offset
                             (mode, xmode));
@@ -2374,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)
@@ -2574,7 +2610,7 @@ expand_debug_expr (tree exp)
              op0 = simplify_gen_unary (FIX, mode, op0, inner_mode);
          }
        else if (CONSTANT_P (op0)
-                || GET_MODE_BITSIZE (mode) <= GET_MODE_BITSIZE (inner_mode))
+                || GET_MODE_PRECISION (mode) <= GET_MODE_PRECISION (inner_mode))
          op0 = simplify_gen_subreg (mode, op0, inner_mode,
                                     subreg_lowpart_offset (mode,
                                                            inner_mode));
@@ -3185,22 +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;
-                     }
+                   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;
              }
@@ -3316,6 +3342,98 @@ expand_debug_expr (tree exp)
     }
 }
 
+/* Return an RTX equivalent to the source bind value of the tree expression
+   EXP.  */
+
+static rtx
+expand_debug_source_expr (tree exp)
+{
+  rtx op0 = NULL_RTX;
+  enum machine_mode mode = VOIDmode, inner_mode;
+
+  switch (TREE_CODE (exp))
+    {
+    case PARM_DECL:
+      {
+       mode = DECL_MODE (exp);
+       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)
+           && !DECL_INCOMING_RTL (exp)
+           && DECL_ABSTRACT_ORIGIN (current_function_decl))
+         {
+           tree aexp = exp;
+           if (DECL_ABSTRACT_ORIGIN (exp))
+             aexp = DECL_ABSTRACT_ORIGIN (exp);
+           if (DECL_CONTEXT (aexp)
+               == DECL_ABSTRACT_ORIGIN (current_function_decl))
+             {
+               VEC(tree, gc) **debug_args;
+               unsigned int ix;
+               tree ddecl;
+#ifdef ENABLE_CHECKING
+               tree parm;
+               for (parm = DECL_ARGUMENTS (current_function_decl);
+                    parm; parm = DECL_CHAIN (parm))
+                 gcc_assert (parm != exp
+                             && DECL_ABSTRACT_ORIGIN (parm) != aexp);
+#endif
+               debug_args = decl_debug_args_lookup (current_function_decl);
+               if (debug_args != NULL)
+                 {
+                   for (ix = 0; VEC_iterate (tree, *debug_args, ix, ddecl);
+                        ix += 2)
+                     if (ddecl == aexp)
+                       return gen_rtx_DEBUG_PARAMETER_REF (mode, aexp);
+                 }
+             }
+         }
+       break;
+      }
+    default:
+      break;
+    }
+
+  if (op0 == NULL_RTX)
+    return NULL_RTX;
+
+  inner_mode = GET_MODE (op0);
+  if (mode == inner_mode)
+    return op0;
+
+  if (FLOAT_MODE_P (mode) && FLOAT_MODE_P (inner_mode))
+    {
+      if (GET_MODE_BITSIZE (mode) == GET_MODE_BITSIZE (inner_mode))
+       op0 = simplify_gen_subreg (mode, op0, inner_mode, 0);
+      else if (GET_MODE_BITSIZE (mode) < GET_MODE_BITSIZE (inner_mode))
+       op0 = simplify_gen_unary (FLOAT_TRUNCATE, mode, op0, inner_mode);
+      else
+       op0 = simplify_gen_unary (FLOAT_EXTEND, mode, op0, inner_mode);
+    }
+  else if (FLOAT_MODE_P (mode))
+    gcc_unreachable ();
+  else if (FLOAT_MODE_P (inner_mode))
+    {
+      if (TYPE_UNSIGNED (TREE_TYPE (exp)))
+       op0 = simplify_gen_unary (UNSIGNED_FIX, mode, op0, inner_mode);
+      else
+       op0 = simplify_gen_unary (FIX, mode, op0, inner_mode);
+    }
+  else if (CONSTANT_P (op0)
+          || GET_MODE_BITSIZE (mode) <= GET_MODE_BITSIZE (inner_mode))
+    op0 = simplify_gen_subreg (mode, op0, inner_mode,
+                              subreg_lowpart_offset (mode, inner_mode));
+  else if (TYPE_UNSIGNED (TREE_TYPE (exp)))
+    op0 = simplify_gen_unary (ZERO_EXTEND, mode, op0, inner_mode);
+  else
+    op0 = simplify_gen_unary (SIGN_EXTEND, mode, op0, inner_mode);
+
+  return op0;
+}
+
 /* Expand the _LOCs in debug insns.  We run this after expanding all
    regular insns, so that any variables referenced in the function
    will have their DECL_RTLs set.  */
@@ -3343,7 +3461,11 @@ expand_debug_locations (void)
          val = NULL_RTX;
        else
          {
-           val = expand_debug_expr (value);
+           if (INSN_VAR_LOCATION_STATUS (insn)
+               == VAR_INIT_STATUS_UNINITIALIZED)
+             val = expand_debug_source_expr (value);
+           else
+             val = expand_debug_expr (value);
            gcc_assert (last == get_last_insn ());
          }
 
@@ -3625,6 +3747,39 @@ expand_gimple_basic_block (basic_block bb)
          set_curr_insn_source_location (sloc);
          set_curr_insn_block (sblock);
        }
+      else if (gimple_debug_source_bind_p (stmt))
+       {
+         location_t sloc = get_curr_insn_source_location ();
+         tree sblock = get_curr_insn_block ();
+         tree var = gimple_debug_source_bind_get_var (stmt);
+         tree value = gimple_debug_source_bind_get_value (stmt);
+         rtx val;
+         enum machine_mode mode;
+
+         last = get_last_insn ();
+
+         set_curr_insn_source_location (gimple_location (stmt));
+         set_curr_insn_block (gimple_block (stmt));
+
+         mode = DECL_MODE (var);
+
+         val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
+                                     VAR_INIT_STATUS_UNINITIALIZED);
+
+         emit_debug_insn (val);
+
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             /* We can't dump the insn with a TREE where an RTX
+                is expected.  */
+             PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+             maybe_dump_rtl_for_gimple_stmt (stmt, last);
+             PAT_VAR_LOCATION_LOC (val) = (rtx)value;
+           }
+
+         set_curr_insn_source_location (sloc);
+         set_curr_insn_block (sblock);
+       }
       else
        {
          if (is_gimple_call (stmt) && gimple_call_tail_p (stmt))
@@ -4292,7 +4447,6 @@ struct rtl_opt_pass pass_expand =
   PROP_ssa | PROP_trees,               /* properties_destroyed */
   TODO_verify_ssa | TODO_verify_flow
     | TODO_verify_stmts,               /* todo_flags_start */
-  TODO_dump_func
-  | TODO_ggc_collect                   /* todo_flags_finish */
+  TODO_ggc_collect                     /* todo_flags_finish */
  }
 };