OSDN Git Service

(c_sizeof, build_c_cast): Set TREE_OVERFLOW in addition
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 144eb63..f8cb7b4 100644 (file)
@@ -41,7 +41,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #ifdef PUSH_ROUNDING
 
-#if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNARD)
+#if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD)
 #define PUSH_ARGS_REVERSED     /* If it's last to first */
 #endif
 
@@ -2205,6 +2205,22 @@ expand_assignment (to, from, want_value, suggest_reg)
              : result);
     }
 
+  /* If the rhs is a function call and its value is not an aggregate,
+     call the function before we start to compute the lhs.
+     This is needed for correct code for cases such as
+     val = setjmp (buf) on machines where reference to val
+     requires loading up part of an address in a separate insn.  */
+  if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from))
+    {
+      rtx value = expand_expr (from, NULL_RTX, VOIDmode, 0);
+      if (to_rtx == 0)
+       to_rtx = expand_expr (to, NULL_RTX, VOIDmode, 0);
+      emit_move_insn (to_rtx, value);
+      preserve_temp_slots (to_rtx);
+      free_temp_slots ();
+      return to_rtx;
+    }
+
   /* Ordinary treatment.  Expand TO to get a REG or MEM rtx.
      Don't re-expand if it was expanded already (in COMPONENT_REF case).  */
 
@@ -2502,12 +2518,14 @@ store_constructor (exp, target)
     }
 #endif
 
-  if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE)
+  if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
+      || TREE_CODE (type) == QUAL_UNION_TYPE)
     {
       register tree elt;
 
       /* Inform later passes that the whole union value is dead.  */
-      if (TREE_CODE (type) == UNION_TYPE)
+      if (TREE_CODE (type) == UNION_TYPE
+         || TREE_CODE (type) == QUAL_UNION_TYPE)
        emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
 
       /* If we are building a static constructor into a register,
@@ -2683,7 +2701,14 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
   if (mode == VOIDmode
       || (mode != BLKmode && ! direct_store[(int) mode])
       || GET_CODE (target) == REG
-      || GET_CODE (target) == SUBREG)
+      || GET_CODE (target) == SUBREG
+      /* If the field isn't aligned enough to fetch as a unit,
+        fetch it as a bit field.  */
+#ifdef STRICT_ALIGNMENT
+      || align * BITS_PER_UNIT < GET_MODE_ALIGNMENT (mode)
+      || bitpos % GET_MODE_ALIGNMENT (mode) != 0
+#endif
+      )
     {
       rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
       /* Store the value in the bitfield.  */
@@ -3126,7 +3151,8 @@ safe_from_p (x, exp)
       switch (TREE_CODE (exp))
        {
        case ADDR_EXPR:
-         return staticp (TREE_OPERAND (exp, 0));
+         return (staticp (TREE_OPERAND (exp, 0))
+                 || safe_from_p (x, TREE_OPERAND (exp, 0)));
 
        case INDIRECT_REF:
          if (GET_CODE (x) == MEM)
@@ -3321,14 +3347,15 @@ expand_expr (exp, target, tmode, modifier)
           the first. */
        return expand_expr (TREE_OPERAND (exp, 0), const0_rtx,
                            VOIDmode, modifier);
-      /* If will do cse, generate all results into pseudo registers
-        since 1) that allows cse to find more things
-        and 2) otherwise cse could produce an insn the machine
-        cannot support.  */
 
       target = 0, original_target = 0;
     }
 
+  /* If will do cse, generate all results into pseudo registers
+     since 1) that allows cse to find more things
+     and 2) otherwise cse could produce an insn the machine
+     cannot support.  */
+
   if (! cse_not_expected && mode != BLKmode && target
       && (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER))
     target = subtarget;
@@ -3373,9 +3400,15 @@ expand_expr (exp, target, tmode, modifier)
     case RESULT_DECL:
       if (DECL_RTL (exp) == 0)
        abort ();
-      /* Ensure variable marked as used
-        even if it doesn't go through a parser.  */
-      TREE_USED (exp) = 1;
+      /* Ensure variable marked as used even if it doesn't go through
+        a parser.  If it hasn't be used yet, write out an external
+        definition.  */
+      if (! TREE_USED (exp))
+       {
+         assemble_external (exp);
+         TREE_USED (exp) = 1;
+       }
+
       /* Handle variables inherited from containing functions.  */
       context = decl_function_context (exp);
 
@@ -3574,13 +3607,8 @@ expand_expr (exp, target, tmode, modifier)
       return SAVE_EXPR_RTL (exp);
 
     case EXIT_EXPR:
-      /* Exit the current loop if the body-expression is true.  */
-      {
-       rtx label = gen_label_rtx ();
-       do_jump (TREE_OPERAND (exp, 0), label, NULL_RTX);
-       expand_exit_loop (NULL_PTR);
-       emit_label (label);
-      }
+      expand_exit_loop_if_false (NULL_PTR,
+                                invert_truthvalue (TREE_OPERAND (exp, 0)));
       return const0_rtx;
 
     case LOOP_EXPR:
@@ -4285,30 +4313,38 @@ expand_expr (exp, target, tmode, modifier)
         address.
 
         If this is an EXPAND_SUM call, always return the sum.  */
-      if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
-         && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
-             || mode == Pmode))
+      if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
+         || mode == Pmode)
        {
-         op1 = expand_expr (TREE_OPERAND (exp, 1), subtarget, VOIDmode,
-                            EXPAND_SUM);
-         op1 = plus_constant (op1, TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)));
-         if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
-           op1 = force_operand (op1, target);
-         return op1;
-       }
+         if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
+             && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+             && TREE_CONSTANT (TREE_OPERAND (exp, 1)))
+           {
+             op1 = expand_expr (TREE_OPERAND (exp, 1), subtarget, VOIDmode,
+                                EXPAND_SUM);
+             op1 = plus_constant (op1, TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)));
+             if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
+               op1 = force_operand (op1, target);
+             return op1;
+           }
 
-      else if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
-              && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT
-              && (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
-                  || mode == Pmode))
-       {
-         op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
-                            EXPAND_SUM);
-         op0 = plus_constant (op0, TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)));
-         if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
-           op0 = force_operand (op0, target);
-         return op0;
+         else if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
+                  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT
+                  && TREE_CONSTANT (TREE_OPERAND (exp, 0)))
+           {
+             op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
+                                EXPAND_SUM);
+             if (! CONSTANT_P (op0))
+               {
+                 op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
+                                    VOIDmode, modifier);
+                 goto both_summands;
+               }
+             op0 = plus_constant (op0, TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)));
+             if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
+               op0 = force_operand (op0, target);
+             return op0;
+           }
        }
 
       /* No sense saving up arithmetic to be done
@@ -4316,7 +4352,8 @@ expand_expr (exp, target, tmode, modifier)
         And force_operand won't know whether to sign-extend or
         zero-extend.  */
       if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
-         || mode != Pmode) goto binop;
+         || mode != Pmode)
+       goto binop;
 
       preexpand_calls (exp);
       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
@@ -4325,6 +4362,7 @@ expand_expr (exp, target, tmode, modifier)
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, modifier);
 
+    both_summands:
       /* Make sure any term that's a sum with a constant comes last.  */
       if (GET_CODE (op0) == PLUS
          && CONSTANT_P (XEXP (op0, 1)))
@@ -4765,18 +4803,25 @@ expand_expr (exp, target, tmode, modifier)
 
     case TRUTH_ANDIF_EXPR:
     case TRUTH_ORIF_EXPR:
-      if (target == 0 || ! safe_from_p (target, exp)
-         /* Make sure we don't have a hard reg (such as function's return
-            value) live across basic blocks, if not optimizing.  */
-         || (!optimize && GET_CODE (target) == REG
-             && REGNO (target) < FIRST_PSEUDO_REGISTER))
+      if (! ignore
+         && (target == 0 || ! safe_from_p (target, exp)
+             /* Make sure we don't have a hard reg (such as function's return
+                value) live across basic blocks, if not optimizing.  */
+             || (!optimize && GET_CODE (target) == REG
+                 && REGNO (target) < FIRST_PSEUDO_REGISTER)))
        target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
-      emit_clr_insn (target);
+
+      if (target)
+       emit_clr_insn (target);
+
       op1 = gen_label_rtx ();
       jumpifnot (exp, op1);
-      emit_0_to_1_insn (target);
+
+      if (target)
+       emit_0_to_1_insn (target);
+
       emit_label (op1);
-      return target;
+      return ignore ? const0_rtx : target;
 
     case TRUTH_NOT_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
@@ -6811,6 +6856,7 @@ expand_increment (exp, post)
   int icode;
   enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
   int op0_is_copy = 0;
+  int single_insn = 0;
 
   /* Stabilize any component ref that might need to be
      evaluated more than once below.  */
@@ -6849,12 +6895,25 @@ expand_increment (exp, post)
       || TREE_CODE (exp) == PREDECREMENT_EXPR)
     this_optab = sub_optab;
 
+  /* For a preincrement, see if we can do this with a single instruction.  */
+  if (!post)
+    {
+      icode = (int) this_optab->handlers[(int) mode].insn_code;
+      if (icode != (int) CODE_FOR_nothing
+         /* Make sure that OP0 is valid for operands 0 and 1
+            of the insn we want to queue.  */
+         && (*insn_operand_predicate[icode][0]) (op0, mode)
+         && (*insn_operand_predicate[icode][1]) (op0, mode)
+         && (*insn_operand_predicate[icode][2]) (op1, mode))
+       single_insn = 1;
+    }
+
   /* If OP0 is not the actual lvalue, but rather a copy in a register,
      then we cannot just increment OP0.  We must therefore contrive to
      increment the original value.  Then, for postincrement, we can return
-     OP0 since it is a copy of the old value.  For preincrement, we want
-     to always expand here, since this generates better or equivalent code.  */
-  if (!post || op0_is_copy)
+     OP0 since it is a copy of the old value.  For preincrement, expand here
+     unless we can do it with a single insn.  */
+  if (op0_is_copy || (!post && !single_insn))
     {
       /* This is the easiest way to increment the value wherever it is.
         Problems with multiple evaluation of INCREMENTED are prevented
@@ -7864,30 +7923,57 @@ do_store_flag (exp, target, mode, only_cheap)
       && integer_pow2p (TREE_OPERAND (arg0, 1))
       && TYPE_PRECISION (type) <= HOST_BITS_PER_WIDE_INT)
     {
+      tree inner = TREE_OPERAND (arg0, 0);
       int bitnum = exact_log2 (INTVAL (expand_expr (TREE_OPERAND (arg0, 1),
                                                    NULL_RTX, VOIDmode, 0)));
+      int ops_unsignedp;
+
+      /* If INNER is a right shift of a constant and it plus BITNUM does
+        not overflow, adjust BITNUM and INNER.  */
+
+      if (TREE_CODE (inner) == RSHIFT_EXPR
+         && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST
+         && TREE_INT_CST_HIGH (TREE_OPERAND (inner, 1)) == 0
+         && (bitnum + TREE_INT_CST_LOW (TREE_OPERAND (inner, 1))
+             < TYPE_PRECISION (type)))
+       {
+         bitnum +=TREE_INT_CST_LOW (TREE_OPERAND (inner, 1));
+         inner = TREE_OPERAND (inner, 0);
+       }
+
+      /* If we are going to be able to omit the AND below, we must do our
+        operations as unsigned.  If we must use the AND, we have a choice.
+        Normally unsigned is faster, but for some machines signed is.  */
+      ops_unsignedp = (bitnum == TYPE_PRECISION (type) - 1 ? 1
+#ifdef BYTE_LOADS_SIGN_EXTEND
+                      : 0
+#else
+                      : 1
+#endif
+                      );
 
       if (subtarget == 0 || GET_CODE (subtarget) != REG
          || GET_MODE (subtarget) != operand_mode
-         || ! safe_from_p (subtarget, TREE_OPERAND (arg0, 0)))
+         || ! safe_from_p (subtarget, inner))
        subtarget = 0;
 
-      op0 = expand_expr (TREE_OPERAND (arg0, 0), subtarget, VOIDmode, 0);
+      op0 = expand_expr (inner, subtarget, VOIDmode, 0);
 
       if (bitnum != 0)
        op0 = expand_shift (RSHIFT_EXPR, GET_MODE (op0), op0,
-                           size_int (bitnum), target, 1);
+                           size_int (bitnum), target, ops_unsignedp);
 
       if (GET_MODE (op0) != mode)
-       op0 = convert_to_mode (mode, op0, 1);
+       op0 = convert_to_mode (mode, op0, ops_unsignedp);
+
+      if ((code == EQ && ! invert) || (code == NE && invert))
+       op0 = expand_binop (mode, xor_optab, op0, const1_rtx, target,
+                           ops_unsignedp, OPTAB_LIB_WIDEN);
 
+      /* Put the AND last so it can combine with more things.  */
       if (bitnum != TYPE_PRECISION (type) - 1)
        op0 = expand_and (op0, const1_rtx, target);
 
-      if ((code == EQ && ! invert) || (code == NE && invert))
-       op0 = expand_binop (mode, xor_optab, op0, const1_rtx, target, 0,
-                           OPTAB_LIB_WIDEN);
-
       return op0;
     }