OSDN Git Service

Always dereference nil receiver passed to value method.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 7e611bd..e4bb633 100644 (file)
@@ -2184,13 +2184,12 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
    to by CALL_FUSAGE.  REG must denote a hard register.  */
 
 void
-use_reg (rtx *call_fusage, rtx reg)
+use_reg_mode (rtx *call_fusage, rtx reg, enum machine_mode mode)
 {
   gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER);
 
   *call_fusage
-    = gen_rtx_EXPR_LIST (VOIDmode,
-                        gen_rtx_USE (VOIDmode, reg), *call_fusage);
+    = gen_rtx_EXPR_LIST (mode, gen_rtx_USE (VOIDmode, reg), *call_fusage);
 }
 
 /* Add USE expressions to *CALL_FUSAGE for each of NREGS consecutive regs,
@@ -3548,131 +3547,151 @@ mem_autoinc_base (rtx mem)
    verified, via immediate operand or auto-inc.  If the adjustment
    cannot be trivially extracted, the return value is INT_MIN.  */
 
-int
-fixup_args_size_notes (rtx prev, rtx last, int end_args_size)
+HOST_WIDE_INT
+find_args_size_adjust (rtx insn)
 {
-  int args_size = end_args_size;
-  bool saw_unknown = false;
-  rtx insn;
+  rtx dest, set, pat;
+  int i;
 
-  for (insn = last; insn != prev; insn = PREV_INSN (insn))
-    {
-      rtx dest, set, pat;
-      HOST_WIDE_INT this_delta = 0;
-      int i;
+  pat = PATTERN (insn);
+  set = NULL;
 
-      if (!NONDEBUG_INSN_P (insn))
-       continue;
-      pat = PATTERN (insn);
-      set = NULL;
+  /* Look for a call_pop pattern.  */
+  if (CALL_P (insn))
+    {
+      /* We have to allow non-call_pop patterns for the case
+        of emit_single_push_insn of a TLS address.  */
+      if (GET_CODE (pat) != PARALLEL)
+       return 0;
 
-      /* Look for a call_pop pattern.  */
-      if (CALL_P (insn))
+      /* All call_pop have a stack pointer adjust in the parallel.
+        The call itself is always first, and the stack adjust is
+        usually last, so search from the end.  */
+      for (i = XVECLEN (pat, 0) - 1; i > 0; --i)
        {
-          /* We have to allow non-call_pop patterns for the case
-            of emit_single_push_insn of a TLS address.  */
-         if (GET_CODE (pat) != PARALLEL)
+         set = XVECEXP (pat, 0, i);
+         if (GET_CODE (set) != SET)
            continue;
-
-         /* All call_pop have a stack pointer adjust in the parallel.
-            The call itself is always first, and the stack adjust is
-            usually last, so search from the end.  */
-         for (i = XVECLEN (pat, 0) - 1; i > 0; --i)
-           {
-             set = XVECEXP (pat, 0, i);
-             if (GET_CODE (set) != SET)
-               continue;
-             dest = SET_DEST (set);
-             if (dest == stack_pointer_rtx)
-               break;
-           }
-         /* We'd better have found the stack pointer adjust.  */
-         if (i == 0)
-           continue;
-         /* Fall through to process the extracted SET and DEST
-            as if it was a standalone insn.  */
+         dest = SET_DEST (set);
+         if (dest == stack_pointer_rtx)
+           break;
        }
-      else if (GET_CODE (pat) == SET)
-       set = pat;
-      else if ((set = single_set (insn)) != NULL)
-       ;
-      else if (GET_CODE (pat) == PARALLEL)
+      /* We'd better have found the stack pointer adjust.  */
+      if (i == 0)
+       return 0;
+      /* Fall through to process the extracted SET and DEST
+        as if it was a standalone insn.  */
+    }
+  else if (GET_CODE (pat) == SET)
+    set = pat;
+  else if ((set = single_set (insn)) != NULL)
+    ;
+  else if (GET_CODE (pat) == PARALLEL)
+    {
+      /* ??? Some older ports use a parallel with a stack adjust
+        and a store for a PUSH_ROUNDING pattern, rather than a
+        PRE/POST_MODIFY rtx.  Don't force them to update yet...  */
+      /* ??? See h8300 and m68k, pushqi1.  */
+      for (i = XVECLEN (pat, 0) - 1; i >= 0; --i)
        {
-         /* ??? Some older ports use a parallel with a stack adjust
-            and a store for a PUSH_ROUNDING pattern, rather than a
-            PRE/POST_MODIFY rtx.  Don't force them to update yet...  */
-         /* ??? See h8300 and m68k, pushqi1.  */
-         for (i = XVECLEN (pat, 0) - 1; i >= 0; --i)
-           {
-             set = XVECEXP (pat, 0, i);
-             if (GET_CODE (set) != SET)
-               continue;
-             dest = SET_DEST (set);
-             if (dest == stack_pointer_rtx)
-               break;
-
-             /* We do not expect an auto-inc of the sp in the parallel.  */
-             gcc_checking_assert (mem_autoinc_base (dest)
-                                  != stack_pointer_rtx);
-             gcc_checking_assert (mem_autoinc_base (SET_SRC (set))
-                                  != stack_pointer_rtx);
-           }
-         if (i < 0)
+         set = XVECEXP (pat, 0, i);
+         if (GET_CODE (set) != SET)
            continue;
+         dest = SET_DEST (set);
+         if (dest == stack_pointer_rtx)
+           break;
+
+         /* We do not expect an auto-inc of the sp in the parallel.  */
+         gcc_checking_assert (mem_autoinc_base (dest) != stack_pointer_rtx);
+         gcc_checking_assert (mem_autoinc_base (SET_SRC (set))
+                              != stack_pointer_rtx);
        }
+      if (i < 0)
+       return 0;
+    }
+  else
+    return 0;
+
+  dest = SET_DEST (set);
+
+  /* Look for direct modifications of the stack pointer.  */
+  if (REG_P (dest) && REGNO (dest) == STACK_POINTER_REGNUM)
+    {
+      /* Look for a trivial adjustment, otherwise assume nothing.  */
+      /* Note that the SPU restore_stack_block pattern refers to
+        the stack pointer in V4SImode.  Consider that non-trivial.  */
+      if (SCALAR_INT_MODE_P (GET_MODE (dest))
+         && GET_CODE (SET_SRC (set)) == PLUS
+         && XEXP (SET_SRC (set), 0) == stack_pointer_rtx
+         && CONST_INT_P (XEXP (SET_SRC (set), 1)))
+       return INTVAL (XEXP (SET_SRC (set), 1));
+      /* ??? Reload can generate no-op moves, which will be cleaned
+        up later.  Recognize it and continue searching.  */
+      else if (rtx_equal_p (dest, SET_SRC (set)))
+       return 0;
       else
-       continue;
-      dest = SET_DEST (set);
-
-      /* Look for direct modifications of the stack pointer.  */
-      if (REG_P (dest) && REGNO (dest) == STACK_POINTER_REGNUM)
-       {
-         gcc_assert (!saw_unknown);
-         /* Look for a trivial adjustment, otherwise assume nothing.  */
-         /* Note that the SPU restore_stack_block pattern refers to
-            the stack pointer in V4SImode.  Consider that non-trivial.  */
-         if (SCALAR_INT_MODE_P (GET_MODE (dest))
-             && GET_CODE (SET_SRC (set)) == PLUS
-             && XEXP (SET_SRC (set), 0) == stack_pointer_rtx
-             && CONST_INT_P (XEXP (SET_SRC (set), 1)))
-           this_delta = INTVAL (XEXP (SET_SRC (set), 1));
-         /* ??? Reload can generate no-op moves, which will be cleaned
-            up later.  Recognize it and continue searching.  */
-         else if (rtx_equal_p (dest, SET_SRC (set)))
-           this_delta = 0;
-         else
-           saw_unknown = true;
-       }
+       return HOST_WIDE_INT_MIN;
+    }
+  else
+    {
+      rtx mem, addr;
+
       /* Otherwise only think about autoinc patterns.  */
-      else if (mem_autoinc_base (dest) == stack_pointer_rtx)
+      if (mem_autoinc_base (dest) == stack_pointer_rtx)
        {
-         rtx addr = XEXP (dest, 0);
-         gcc_assert (!saw_unknown);
-         switch (GET_CODE (addr))
-           {
-           case PRE_INC:
-           case POST_INC:
-             this_delta = GET_MODE_SIZE (GET_MODE (dest));
-             break;
-           case PRE_DEC:
-           case POST_DEC:
-             this_delta = -GET_MODE_SIZE (GET_MODE (dest));
-             break;
-           case PRE_MODIFY:
-           case POST_MODIFY:
-             addr = XEXP (addr, 1);
-             gcc_assert (GET_CODE (addr) == PLUS);
-             gcc_assert (XEXP (addr, 0) == stack_pointer_rtx);
-             gcc_assert (CONST_INT_P (XEXP (addr, 1)));
-             this_delta = INTVAL (XEXP (addr, 1));
-             break;
-           default:
-             gcc_unreachable ();
-           }
+         mem = dest;
+         gcc_checking_assert (mem_autoinc_base (SET_SRC (set))
+                              != stack_pointer_rtx);
        }
+      else if (mem_autoinc_base (SET_SRC (set)) == stack_pointer_rtx)
+       mem = SET_SRC (set);
       else
+       return 0;
+
+      addr = XEXP (mem, 0);
+      switch (GET_CODE (addr))
+       {
+       case PRE_INC:
+       case POST_INC:
+         return GET_MODE_SIZE (GET_MODE (mem));
+       case PRE_DEC:
+       case POST_DEC:
+         return -GET_MODE_SIZE (GET_MODE (mem));
+       case PRE_MODIFY:
+       case POST_MODIFY:
+         addr = XEXP (addr, 1);
+         gcc_assert (GET_CODE (addr) == PLUS);
+         gcc_assert (XEXP (addr, 0) == stack_pointer_rtx);
+         gcc_assert (CONST_INT_P (XEXP (addr, 1)));
+         return INTVAL (XEXP (addr, 1));
+       default:
+         gcc_unreachable ();
+       }
+    }
+}
+
+int
+fixup_args_size_notes (rtx prev, rtx last, int end_args_size)
+{
+  int args_size = end_args_size;
+  bool saw_unknown = false;
+  rtx insn;
+
+  for (insn = last; insn != prev; insn = PREV_INSN (insn))
+    {
+      HOST_WIDE_INT this_delta;
+
+      if (!NONDEBUG_INSN_P (insn))
+       continue;
+
+      this_delta = find_args_size_adjust (insn);
+      if (this_delta == 0)
        continue;
 
+      gcc_assert (!saw_unknown);
+      if (this_delta == HOST_WIDE_INT_MIN)
+       saw_unknown = true;
+
       add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (args_size));
 #ifdef STACK_GROWS_DOWNWARD
       this_delta = -this_delta;
@@ -4354,7 +4373,8 @@ get_bit_range (unsigned HOST_WIDE_INT *bitstart,
           || TREE_CODE (innerdecl) == TARGET_MEM_REF)
          && !ptr_deref_may_alias_global_p (TREE_OPERAND (innerdecl, 0)))
       || (DECL_P (innerdecl)
-         && (DECL_THREAD_LOCAL_P (innerdecl)
+         && ((TREE_CODE (innerdecl) == VAR_DECL
+              && DECL_THREAD_LOCAL_P (innerdecl))
              || !TREE_STATIC (innerdecl))))
     {
       *bitstart = *bitend = 0;
@@ -8003,19 +8023,16 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
        {
          enum machine_mode innermode = TYPE_MODE (TREE_TYPE (treeop0));
          this_optab = usmul_widen_optab;
-         if (mode == GET_MODE_2XWIDER_MODE (innermode))
+         if (find_widening_optab_handler (this_optab, mode, innermode, 0)
+               != CODE_FOR_nothing)
            {
-             if (widening_optab_handler (this_optab, mode, innermode)
-                   != CODE_FOR_nothing)
-               {
-                 if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))
-                   expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
-                                    EXPAND_NORMAL);
-                 else
-                   expand_operands (treeop0, treeop1, NULL_RTX, &op1, &op0,
-                                    EXPAND_NORMAL);
-                 goto binop3;
-               }
+             if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))
+               expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
+                                EXPAND_NORMAL);
+             else
+               expand_operands (treeop0, treeop1, NULL_RTX, &op1, &op0,
+                                EXPAND_NORMAL);
+             goto binop3;
            }
        }
       /* Check for a multiplication with matching signedness.  */
@@ -8030,10 +8047,9 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
          optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
          this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;
 
-         if (mode == GET_MODE_2XWIDER_MODE (innermode)
-             && TREE_CODE (treeop0) != INTEGER_CST)
+         if (TREE_CODE (treeop0) != INTEGER_CST)
            {
-             if (widening_optab_handler (this_optab, mode, innermode)
+             if (find_widening_optab_handler (this_optab, mode, innermode, 0)
                    != CODE_FOR_nothing)
                {
                  expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
@@ -8042,7 +8058,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
                                               unsignedp, this_optab);
                  return REDUCE_BIT_FIELD (temp);
                }
-             if (widening_optab_handler (other_optab, mode, innermode)
+             if (find_widening_optab_handler (other_optab, mode, innermode, 0)
                    != CODE_FOR_nothing
                  && innermode == word_mode)
                {
@@ -8619,6 +8635,64 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
         return temp;
       }
 
+    case COND_EXPR:
+      /* A COND_EXPR with its type being VOID_TYPE represents a
+        conditional jump and is handled in
+        expand_gimple_cond_expr.  */
+      gcc_assert (!VOID_TYPE_P (type));
+
+      /* Note that COND_EXPRs whose type is a structure or union
+        are required to be constructed to contain assignments of
+        a temporary variable, so that we can evaluate them here
+        for side effect only.  If type is void, we must do likewise.  */
+
+      gcc_assert (!TREE_ADDRESSABLE (type)
+                 && !ignore
+                 && TREE_TYPE (treeop1) != void_type_node
+                 && TREE_TYPE (treeop2) != void_type_node);
+
+      /* If we are not to produce a result, we have no target.  Otherwise,
+        if a target was specified use it; it will not be used as an
+        intermediate target unless it is safe.  If no target, use a
+        temporary.  */
+
+      if (modifier != EXPAND_STACK_PARM
+         && original_target
+         && safe_from_p (original_target, treeop0, 1)
+         && GET_MODE (original_target) == mode
+#ifdef HAVE_conditional_move
+         && (! can_conditionally_move_p (mode)
+             || REG_P (original_target))
+#endif
+         && !MEM_P (original_target))
+       temp = original_target;
+      else
+       temp = assign_temp (type, 0, 0, 1);
+
+      do_pending_stack_adjust ();
+      NO_DEFER_POP;
+      op0 = gen_label_rtx ();
+      op1 = gen_label_rtx ();
+      jumpifnot (treeop0, op0, -1);
+      store_expr (treeop1, temp,
+                 modifier == EXPAND_STACK_PARM,
+                 false);
+
+      emit_jump_insn (gen_jump (op1));
+      emit_barrier ();
+      emit_label (op0);
+      store_expr (treeop2, temp,
+                 modifier == EXPAND_STACK_PARM,
+                 false);
+
+      emit_label (op1);
+      OK_DEFER_POP;
+      return temp;
+
+    case VEC_COND_EXPR:
+      target = expand_vec_cond_expr (type, treeop0, treeop1, treeop2, target);
+      return target;
+
     default:
       gcc_unreachable ();
     }
@@ -9861,64 +9935,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
       return op0;
 
-    case COND_EXPR:
-      /* A COND_EXPR with its type being VOID_TYPE represents a
-        conditional jump and is handled in
-        expand_gimple_cond_expr.  */
-      gcc_assert (!VOID_TYPE_P (type));
-
-        /* Note that COND_EXPRs whose type is a structure or union
-        are required to be constructed to contain assignments of
-        a temporary variable, so that we can evaluate them here
-        for side effect only.  If type is void, we must do likewise.  */
-
-        gcc_assert (!TREE_ADDRESSABLE (type)
-                   && !ignore
-                   && TREE_TYPE (treeop1) != void_type_node
-                   && TREE_TYPE (treeop2) != void_type_node);
-
-       /* If we are not to produce a result, we have no target.  Otherwise,
-        if a target was specified use it; it will not be used as an
-        intermediate target unless it is safe.  If no target, use a
-        temporary.  */
-
-       if (modifier != EXPAND_STACK_PARM
-         && original_target
-         && safe_from_p (original_target, treeop0, 1)
-         && GET_MODE (original_target) == mode
-#ifdef HAVE_conditional_move
-         && (! can_conditionally_move_p (mode)
-             || REG_P (original_target))
-#endif
-         && !MEM_P (original_target))
-       temp = original_target;
-       else
-       temp = assign_temp (type, 0, 0, 1);
-
-       do_pending_stack_adjust ();
-       NO_DEFER_POP;
-       op0 = gen_label_rtx ();
-       op1 = gen_label_rtx ();
-       jumpifnot (treeop0, op0, -1);
-       store_expr (treeop1, temp,
-                 modifier == EXPAND_STACK_PARM,
-                 false);
-
-       emit_jump_insn (gen_jump (op1));
-       emit_barrier ();
-       emit_label (op0);
-       store_expr (treeop2, temp,
-                 modifier == EXPAND_STACK_PARM,
-                 false);
-
-       emit_label (op1);
-       OK_DEFER_POP;
-       return temp;
-
-    case VEC_COND_EXPR:
-      target = expand_vec_cond_expr (type, treeop0, treeop1, treeop2, target);
-      return target;
-
     case MODIFY_EXPR:
       {
        tree lhs = treeop0;
@@ -10151,6 +10167,17 @@ string_constant (tree arg, tree *ptr_offset)
                                    fold_convert (sizetype, lower_bound));
            }
        }
+      else if (TREE_CODE (TREE_OPERAND (arg, 0)) == MEM_REF)
+       {
+         array = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+         offset = TREE_OPERAND (TREE_OPERAND (arg, 0), 1);
+         if (TREE_CODE (array) != ADDR_EXPR)
+           return 0;
+         array = TREE_OPERAND (array, 0);
+         if (TREE_CODE (array) != STRING_CST
+             && TREE_CODE (array) != VAR_DECL)
+           return 0;
+       }
       else
        return 0;
     }