This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

argument slot saving code, patch 2


Problem synopsis: On targets that define ACCUMULATE_OUTGOING_ARGS, g++
may save and restore the argument area around a libcall memcpy used to
put a structure passed by value in the arg area.  The arg area restore
of course zaps the copy of the structure.  Testcase at
http://gcc.gnu.org/ml/gcc-patches/2003-01/txt00033.txt

A related problem is that the hack to avoid this when compiling C code
(See comment starting "Special handling" in calls.c) results in
inefficient code.  The reason why this hack doesn't work for C++ is
that g++ wraps the structure VAR_DECL in a TARGET_EXPR, resulting in
the structure being copied in expand_expr rather than later via
emit_push_insn in store_one_arg.

The best solution I could arrive at is to revert Jeff's patch which
marks the arg area as used _before_ the memcpy, and avoid the original
mn102/mn103 problem he was fixing by changes to expand_expr.  My idea
is to pass a new EXPAND_STACK_PARM modifier to expand_expr from the
call in store_one_arg, which has the effect of only using "target" for
the final destination.  A side benefit is that the hack I mention
above can go too.

Another side-benefit is that Richard's BLOCK_OP_CALL_PARM
emit_block_move optimization can be made effective for g++.  As
mentioned above, the structure copy happens in expand_expr, not
in emit_push_insn where BLOCK_OP_CALL_PARM is set.

	* calls.c (store_one_arg): Revert 1999-02-16 change.  Revert
	2000-12-17 change.  Pass EXPAND_STACK_PARM to expand_expr.
	* expr.h (enum expand_modifier): Define EXPAND_STACK_PARM.
	(enum block_op_methods): Reorder for better store_expr optimization.
	* expr.c (store_expr): Test bit 1 of "want_value" for call param
	stores, test bit 0 for original want_value meaning.  Pass
	BLOCK_OP_CALL_PARM to emit_block_move when bit 1 set.  Adjust
	recursive calls, and calls to expand_param.
	(expand_expr): Handle EXPAND_STACK_PARM modifier.  When cse
	expected, set target to 0 rather than to subtarget.  Formatting.

Note: setting target to 0 doesn't change anything as subtarget is 0 in
this case.  It's just a little clearer what is going on.

diff -urpN -xCVS -x'*~' -x'.#*' gcc-current/gcc/calls.c gcc-call/gcc/calls.c
--- gcc-current/gcc/calls.c	2003-02-04 12:25:47.000000000 +1030
+++ gcc-call/gcc/calls.c	2003-02-10 13:28:45.000000000 +1030
@@ -4337,13 +4341,6 @@ store_one_arg (arg, argblock, flags, var
 		}
 	    }
 	}
-      /* Now that we have saved any slots that will be overwritten by this
-	 store, mark all slots this store will use.  We must do this before
-	 we actually expand the argument since the expansion itself may
-	 trigger library calls which might need to use the same stack slot.  */
-      if (argblock && ! variable_size && arg->stack)
-	for (i = lower_bound; i < upper_bound; i++)
-	  stack_usage_map[i] = 1;
     }
 
   /* If this isn't going to be placed on both the stack and in registers,
@@ -4396,7 +4393,7 @@ store_one_arg (arg, argblock, flags, var
 				(partial
 				 || TYPE_MODE (TREE_TYPE (pval)) != arg->mode)
 				? NULL_RTX : arg->stack,
-				VOIDmode, 0);
+				VOIDmode, EXPAND_STACK_PARM);
 
       /* If we are promoting object (or for any other reason) the mode
 	 doesn't agree, convert the mode.  */
@@ -4539,37 +4536,6 @@ store_one_arg (arg, argblock, flags, var
 	    }
 	}
 
-      /* Special handling is required if part of the parameter lies in the
-	 register parameter area.  The argument may be copied into the stack
-	 slot using memcpy(), but the original contents of the register
-	 parameter area will be restored after the memcpy() call.
-
-	 To ensure that the part that lies in the register parameter area
-	 is copied correctly, we emit a separate push for that part.  This
-	 push should be small enough to avoid a call to memcpy().  */
-#ifndef STACK_PARMS_IN_REG_PARM_AREA
-      if (arg->reg && arg->pass_on_stack)
-#else
-      if (1)
-#endif
-	{
-	  if (arg->offset.constant < reg_parm_stack_space && arg->offset.var)
-	    error ("variable offset is passed partially in stack and in reg");
-	  else if (arg->offset.constant < reg_parm_stack_space && arg->size.var)
-	    error ("variable size is passed partially in stack and in reg");
-	  else if (arg->offset.constant < reg_parm_stack_space 
-	      && ((arg->offset.constant + arg->size.constant) 
-		   > reg_parm_stack_space))
-          {
-	    rtx size_rtx1 = GEN_INT (reg_parm_stack_space - arg->offset.constant);
-	    emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx1,
-		            parm_align, partial, reg, excess, argblock,
-			    ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
-		            ARGS_SIZE_RTX (arg->alignment_pad));
-	  }
-	}
-	
-
       emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
 		      parm_align, partial, reg, excess, argblock,
 		      ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
@@ -4587,6 +4553,12 @@ store_one_arg (arg, argblock, flags, var
 	arg->value = arg->stack_slot;
     }
 
+  /* Mark all slots this store used.  */
+  if (ACCUMULATE_OUTGOING_ARGS && !(flags & ECF_SIBCALL)
+      && argblock && ! variable_size && arg->stack)
+    for (i = lower_bound; i < upper_bound; i++)
+      stack_usage_map[i] = 1;
+
   /* Once we have pushed something, pops can't safely
      be deferred during the rest of the arguments.  */
   NO_DEFER_POP;
diff -urpN -xCVS -x'*~' -x'.#*' gcc-current/gcc/expr.h gcc-call/gcc/expr.h
--- gcc-current/gcc/expr.h	2003-01-24 10:06:19.000000000 +1030
+++ gcc-call/gcc/expr.h	2003-02-10 13:25:16.000000000 +1030
@@ -44,13 +44,16 @@ Software Foundation, 59 Temple Place - S
 #define QUEUED_NEXT(P) XEXP (P, 4)
 
 /* This is the 4th arg to `expand_expr'.
+   EXPAND_STACK_PARM means we are possibly expanding a call param onto
+   the stack.  Choosing a value of 2 isn't special;  It just allows
+   some code optimization in store_expr.
    EXPAND_SUM means it is ok to return a PLUS rtx or MULT rtx.
    EXPAND_INITIALIZER is similar but also record any labels on forced_labels.
    EXPAND_CONST_ADDRESS means it is ok to return a MEM whose address
     is a constant that is not a legitimate address.
    EXPAND_WRITE means we are only going to write to the resulting rtx.  */
-enum expand_modifier {EXPAND_NORMAL, EXPAND_SUM, EXPAND_CONST_ADDRESS,
-			EXPAND_INITIALIZER, EXPAND_WRITE};
+enum expand_modifier {EXPAND_NORMAL = 0, EXPAND_STACK_PARM = 2, EXPAND_SUM,
+		      EXPAND_CONST_ADDRESS, EXPAND_INITIALIZER, EXPAND_WRITE};
 
 /* Prevent the compiler from deferring stack pops.  See
    inhibit_defer_pop for more information.  */
@@ -378,8 +381,8 @@ extern rtx convert_modes PARAMS ((enum m
 enum block_op_methods
 {
   BLOCK_OP_NORMAL,
-  BLOCK_OP_CALL_PARM,
-  BLOCK_OP_NO_LIBCALL
+  BLOCK_OP_NO_LIBCALL,
+  BLOCK_OP_CALL_PARM
 };
 
 extern rtx emit_block_move PARAMS ((rtx, rtx, rtx, enum block_op_methods));
diff -urpN -xCVS -x'*~' -x'.#*' gcc-current/gcc/expr.c gcc-call/gcc/expr.c
--- gcc-current/gcc/expr.c	2003-02-04 12:25:49.000000000 +1030
+++ gcc-call/gcc/expr.c	2003-02-10 13:27:59.000000000 +1030
@@ -4256,7 +4256,7 @@ expand_assignment (to, from, want_value,
    and storing the value into TARGET.
    TARGET may contain a QUEUED rtx.
 
-   If WANT_VALUE is nonzero, return a copy of the value
+   If WANT_VALUE & 1 is nonzero, return a copy of the value
    not in TARGET, so that we can be sure to use the proper
    value in a containing expression even if TARGET has something
    else stored in it.  If possible, we copy the value through a pseudo
@@ -4271,9 +4271,12 @@ expand_assignment (to, from, want_value,
    with no sequence point.  Will other languages need this to
    be more thorough?
 
-   If WANT_VALUE is 0, we return NULL, to make sure
+   If WANT_VALUE & 1 is 0, we return NULL, to make sure
    to catch quickly any cases where the caller uses the value
-   and fails to set WANT_VALUE.  */
+   and fails to set WANT_VALUE.
+
+   If WANT_VALUE & 2 is set, this is a store into a call param on the
+   stack, and block moves may need to be treated specially.  */
 
 rtx
 store_expr (exp, target, want_value)
@@ -4289,7 +4292,8 @@ store_expr (exp, target, want_value)
     {
       /* Perform first part of compound expression, then assign from second
 	 part.  */
-      expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
+      expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
+		   want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
       emit_queue ();
       return store_expr (TREE_OPERAND (exp, 1), target, want_value);
     }
@@ -4309,20 +4313,20 @@ store_expr (exp, target, want_value)
       NO_DEFER_POP;
       jumpifnot (TREE_OPERAND (exp, 0), lab1);
       start_cleanup_deferral ();
-      store_expr (TREE_OPERAND (exp, 1), target, 0);
+      store_expr (TREE_OPERAND (exp, 1), target, want_value & 2);
       end_cleanup_deferral ();
       emit_queue ();
       emit_jump_insn (gen_jump (lab2));
       emit_barrier ();
       emit_label (lab1);
       start_cleanup_deferral ();
-      store_expr (TREE_OPERAND (exp, 2), target, 0);
+      store_expr (TREE_OPERAND (exp, 2), target, want_value & 2);
       end_cleanup_deferral ();
       emit_queue ();
       emit_label (lab2);
       OK_DEFER_POP;
 
-      return want_value ? target : NULL_RTX;
+      return want_value & 1 ? target : NULL_RTX;
     }
   else if (queued_subexp_p (target))
     /* If target contains a postincrement, let's not risk
@@ -4332,18 +4336,24 @@ store_expr (exp, target, want_value)
 	{
 	  /* Expand EXP into a new pseudo.  */
 	  temp = gen_reg_rtx (GET_MODE (target));
-	  temp = expand_expr (exp, temp, GET_MODE (target), 0);
+	  temp = expand_expr (exp, temp, GET_MODE (target),
+			      (want_value & 2
+			       ? EXPAND_STACK_PARM : EXPAND_NORMAL));
 	}
       else
-	temp = expand_expr (exp, NULL_RTX, GET_MODE (target), 0);
+	temp = expand_expr (exp, NULL_RTX, GET_MODE (target),
+			    (want_value & 2
+			     ? EXPAND_STACK_PARM : EXPAND_NORMAL));
 
       /* If target is volatile, ANSI requires accessing the value
 	 *from* the target, if it is accessed.  So make that happen.
 	 In no case return the target itself.  */
-      if (! MEM_VOLATILE_P (target) && want_value)
+      if (! MEM_VOLATILE_P (target) && (want_value & 1) != 0)
 	dont_return_target = 1;
     }
-  else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
+  else if ((want_value & 1) != 0
+	   && GET_CODE (target) == MEM
+	   && ! MEM_VOLATILE_P (target)
 	   && GET_MODE (target) != BLKmode)
     /* If target is in memory and caller wants value in a register instead,
        arrange that.  Pass TARGET as target for expand_expr so that,
@@ -4352,7 +4362,8 @@ store_expr (exp, target, want_value)
        Don't do this if TARGET is volatile because we are supposed
        to write it and then read it.  */
     {
-      temp = expand_expr (exp, target, GET_MODE (target), 0);
+      temp = expand_expr (exp, target, GET_MODE (target),
+			  want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
       if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
 	{
 	  /* If TEMP is already in the desired TARGET, only copy it from
@@ -4379,7 +4390,8 @@ store_expr (exp, target, want_value)
 	 the extend.  But don't do this if the type of EXP is a subtype
 	 of something else since then the conversion might involve
 	 more than just converting modes.  */
-      if (! want_value && INTEGRAL_TYPE_P (TREE_TYPE (exp))
+      if ((want_value & 1) == 0
+	  && INTEGRAL_TYPE_P (TREE_TYPE (exp))
 	  && TREE_TYPE (TREE_TYPE (exp)) == 0)
 	{
 	  if (TREE_UNSIGNED (TREE_TYPE (exp))
@@ -4396,14 +4408,15 @@ store_expr (exp, target, want_value)
 	  inner_target = SUBREG_REG (target);
 	}
 
-      temp = expand_expr (exp, inner_target, VOIDmode, 0);
+      temp = expand_expr (exp, inner_target, VOIDmode,
+			  want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
 
       /* If TEMP is a MEM and we want a result value, make the access
 	 now so it gets done only once.  Strictly speaking, this is 
 	 only necessary if the MEM is volatile, or if the address 
 	 overlaps TARGET.  But not performing the load twice also
 	 reduces the amount of rtl we generate and then have to CSE.  */
-      if (GET_CODE (temp) == MEM && want_value)
+      if (GET_CODE (temp) == MEM && (want_value & 1) != 0)
 	temp = copy_to_reg (temp);
 
       /* If TEMP is a VOIDmode constant, use convert_modes to make
@@ -4424,7 +4437,7 @@ store_expr (exp, target, want_value)
 	 target.  Otherwise, the caller might get confused by a result whose
 	 mode is larger than expected.  */
 
-      if (want_value && GET_MODE (temp) != GET_MODE (target))
+      if ((want_value & 1) != 0 && GET_MODE (temp) != GET_MODE (target))
 	{
 	  if (GET_MODE (temp) != VOIDmode)
 	    {
@@ -4439,11 +4452,12 @@ store_expr (exp, target, want_value)
 				  temp, SUBREG_PROMOTED_UNSIGNED_P (target));
 	}
 
-      return want_value ? temp : NULL_RTX;
+      return want_value & 1 ? temp : NULL_RTX;
     }
   else
     {
-      temp = expand_expr (exp, target, GET_MODE (target), 0);
+      temp = expand_expr (exp, target, GET_MODE (target),
+			  want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
       /* Return TARGET if it's a specified hardware register.
 	 If TARGET is a volatile mem ref, either return TARGET
 	 or return a reg copied *from* TARGET; ANSI requires this.
@@ -4455,7 +4469,7 @@ store_expr (exp, target, want_value)
 	    && REGNO (target) < FIRST_PSEUDO_REGISTER)
 	  && !(GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
 	  && ! rtx_equal_p (temp, target)
-	  && (CONSTANT_P (temp) || want_value))
+	  && (CONSTANT_P (temp) || (want_value & 1) != 0))
 	dont_return_target = 1;
     }
 
@@ -4526,7 +4540,9 @@ store_expr (exp, target, want_value)
 
 	  if (GET_CODE (size) == CONST_INT
 	      && INTVAL (size) < TREE_STRING_LENGTH (exp))
-	    emit_block_move (target, temp, size, BLOCK_OP_NORMAL);
+	    emit_block_move (target, temp, size,
+			     (want_value & 2
+			      ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
 	  else
 	    {
 	      /* Compute the size of the data to copy from the string.  */
@@ -4534,13 +4550,17 @@ store_expr (exp, target, want_value)
 		= size_binop (MIN_EXPR,
 			      make_tree (sizetype, size),
 			      size_int (TREE_STRING_LENGTH (exp)));
-	      rtx copy_size_rtx = expand_expr (copy_size, NULL_RTX,
-					       VOIDmode, 0);
+	      rtx copy_size_rtx
+		= expand_expr (copy_size, NULL_RTX, VOIDmode,
+			       (want_value & 2
+				? EXPAND_STACK_PARM : EXPAND_NORMAL));
 	      rtx label = 0;
 
 	      /* Copy that much.  */
 	      copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx, 0);
-	      emit_block_move (target, temp, copy_size_rtx, BLOCK_OP_NORMAL);
+	      emit_block_move (target, temp, copy_size_rtx,
+			       (want_value & 2
+				? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
 
 	      /* Figure out how much is left in TARGET that we have to clear.
 		 Do all calculations in ptr_mode.  */
@@ -4581,13 +4601,15 @@ store_expr (exp, target, want_value)
       else if (GET_CODE (target) == PARALLEL)
 	emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)));
       else if (GET_MODE (temp) == BLKmode)
-	emit_block_move (target, temp, expr_size (exp), BLOCK_OP_NORMAL);
+	emit_block_move (target, temp, expr_size (exp),
+			 (want_value & 2
+			  ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
       else
 	emit_move_insn (target, temp);
     }
 
   /* If we don't want a value, return NULL_RTX.  */
-  if (! want_value)
+  if ((want_value & 1) == 0)
     return NULL_RTX;
 
   /* If we are supposed to return TEMP, do so as long as it isn't a MEM.
@@ -4596,7 +4618,8 @@ store_expr (exp, target, want_value)
     return temp;
 
   /* Return TARGET itself if it is a hard register.  */
-  else if (want_value && GET_MODE (target) != BLKmode
+  else if ((want_value & 1) != 0
+	   && GET_MODE (target) != BLKmode
 	   && ! (GET_CODE (target) == REG
 		 && REGNO (target) < FIRST_PSEUDO_REGISTER))
     return copy_to_reg (target);
@@ -6410,7 +6433,14 @@ find_placeholder (exp, plist)
 
    EXPAND_CONST_ADDRESS says that it is okay to return a MEM
    with a constant address even if that address is not normally legitimate.
-   EXPAND_INITIALIZER and EXPAND_SUM also have this effect.  */
+   EXPAND_INITIALIZER and EXPAND_SUM also have this effect.
+
+   EXPAND_STACK_PARM is used when expanding to a TARGET on the stack for
+   a call parameter.  Such targets require special care as we haven't yet
+   marked TARGET so that it's safe from being trashed by libcalls.  We
+   don't want to use TARGET for anything but the final result;
+   Intermediate values must go elsewhere.   Additionally, calls to
+   emit_block_move will be flagged with BLOCK_OP_CALL_PARM.  */
 
 rtx
 expand_expr (exp, target, tmode, modifier)
@@ -6555,7 +6585,7 @@ expand_expr (exp, target, tmode, modifie
       && (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER)
       && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
       && ! (code == CALL_EXPR && aggregate_value_p (exp)))
-    target = subtarget;
+    target = 0;
 
   switch (code)
     {
@@ -6741,7 +6771,7 @@ expand_expr (exp, target, tmode, modifie
       return temp;
 
     case CONST_DECL:
-      return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0);
+      return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
 
     case REAL_CST:
       /* If optimized, generate immediate CONST_DOUBLE
@@ -6857,7 +6887,8 @@ expand_expr (exp, target, tmode, modifie
 	  if (temp == const0_rtx)
 	    expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
 	  else
-	    store_expr (TREE_OPERAND (exp, 0), temp, 0);
+	    store_expr (TREE_OPERAND (exp, 0), temp,
+			modifier == EXPAND_STACK_PARM ? 2 : 0);
 
 	  TREE_USED (exp) = 1;
 	}
@@ -7042,7 +7073,8 @@ expand_expr (exp, target, tmode, modifie
 	  /* Handle calls that pass values in multiple non-contiguous
 	     locations.  The Irix 6 ABI has examples of this.  */
 	  if (target == 0 || ! safe_from_p (target, exp, 1)
-	      || GET_CODE (target) == PARALLEL)
+	      || GET_CODE (target) == PARALLEL
+	      || modifier == EXPAND_STACK_PARM)
 	    target
 	      = assign_temp (build_qualified_type (type,
 						   (TYPE_QUALS (type)
@@ -7216,6 +7248,9 @@ expand_expr (exp, target, tmode, modifie
 			&& (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt)))
 			    <= HOST_BITS_PER_WIDE_INT))))
 	      {
+		if (DECL_BIT_FIELD (TREE_PURPOSE (elt))
+		    && modifier == EXPAND_STACK_PARM)
+		  target = 0;
 		op0 = expand_expr (TREE_VALUE (elt), target, tmode, modifier);
 		if (DECL_BIT_FIELD (TREE_PURPOSE (elt)))
 		  {
@@ -7270,10 +7305,12 @@ expand_expr (exp, target, tmode, modifie
 			 (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
 			  && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
 			      != INTEGER_CST)
+			  && modifier != EXPAND_STACK_PARM
 			  ? target : NULL_RTX),
 			 VOIDmode,
 			 (modifier == EXPAND_INITIALIZER
-			  || modifier == EXPAND_CONST_ADDRESS)
+			  || modifier == EXPAND_CONST_ADDRESS
+			  || modifier == EXPAND_STACK_PARM)
 			 ? modifier : EXPAND_NORMAL);
 
 	/* If this is a constant, put it into a register if it is a
@@ -7290,7 +7327,8 @@ expand_expr (exp, target, tmode, modifie
 
 	if (offset != 0)
 	  {
-	    rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
+	    rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
+					  EXPAND_SUM);
 
 	    /* If this object is in a register, put it into memory.
 	       This case can't occur in C, but can in Ada if we have
@@ -7426,7 +7464,8 @@ expand_expr (exp, target, tmode, modifie
 		emit_block_move (target, op0,
 				 GEN_INT ((bitsize + BITS_PER_UNIT - 1)
 					  / BITS_PER_UNIT),
-				 BLOCK_OP_NORMAL);
+				 (modifier == EXPAND_STACK_PARM
+				  ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
 
 		return target;
 	      }
@@ -7436,8 +7475,10 @@ expand_expr (exp, target, tmode, modifie
 	    if (GET_CODE (op0) == MEM && GET_CODE (XEXP (op0, 0)) == REG)
 	      mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
 
-	    op0 = extract_bit_field (op0, bitsize, bitpos,
-				     unsignedp, target, ext_mode, ext_mode,
+	    op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp,
+				     (modifier == EXPAND_STACK_PARM
+				      ? NULL_RTX : target),
+				     ext_mode, ext_mode,
 				     int_size_in_bytes (TREE_TYPE (tem)));
 
 	    /* If the result is a record type and BITSIZE is narrower than
@@ -7681,8 +7722,8 @@ expand_expr (exp, target, tmode, modifie
 	{
 	  if (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
 	      == BUILT_IN_FRONTEND)
-	    return (*lang_hooks.expand_expr)
-	      (exp, original_target, tmode, modifier);
+	    return (*lang_hooks.expand_expr) (exp, original_target,
+					      tmode, modifier);
 	  else
 	    return expand_builtin (exp, target, subtarget, tmode, ignore);
 	}
@@ -7718,7 +7759,8 @@ expand_expr (exp, target, tmode, modifie
 	  if (GET_CODE (target) == MEM)
 	    /* Store data into beginning of memory target.  */
 	    store_expr (TREE_OPERAND (exp, 0),
-			adjust_address (target, TYPE_MODE (valtype), 0), 0);
+			adjust_address (target, TYPE_MODE (valtype), 0),
+			modifier == EXPAND_STACK_PARM ? 2 : 0);
 
 	  else if (GET_CODE (target) == REG)
 	    /* Store this field into a union of the proper type.  */
@@ -7843,7 +7885,8 @@ expand_expr (exp, target, tmode, modifie
 	      if (GET_MODE (op0) == BLKmode)
 		emit_block_move (new_with_op0_mode, op0,
 				 GEN_INT (GET_MODE_SIZE (TYPE_MODE (type))),
-				 BLOCK_OP_NORMAL);
+				 (modifier == EXPAND_STACK_PARM
+				  ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
 	      else
 		emit_move_insn (new_with_op0_mode, op0);
 
@@ -7895,6 +7938,8 @@ expand_expr (exp, target, tmode, modifie
       if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
 	  || (mode == ptr_mode && (unsignedp || ! flag_trapv)))
 	{
+	  if (modifier == EXPAND_STACK_PARM)
+	    target = 0;
 	  if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
 	      && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
 	      && TREE_CONSTANT (TREE_OPERAND (exp, 1)))
@@ -8115,6 +8160,9 @@ expand_expr (exp, target, tmode, modifie
       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
 	subtarget = 0;
 
+      if (modifier == EXPAND_STACK_PARM)
+	target = 0;
+
       /* Check for multiplying things that have been extended
 	 from a narrower type.  If this machine supports multiplying
 	 in that narrower type with a result in the desired type,
@@ -8198,6 +8246,8 @@ expand_expr (exp, target, tmode, modifie
     case EXACT_DIV_EXPR:
       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
 	subtarget = 0;
+      if (modifier == EXPAND_STACK_PARM)
+	target = 0;
       /* Possible optimization: compute the dividend with EXPAND_SUM
 	 then if the divisor is constant can optimize the case
 	 where some terms of the dividend have coeffs divisible by it.  */
@@ -8226,6 +8276,8 @@ expand_expr (exp, target, tmode, modifie
     case ROUND_MOD_EXPR:
       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
 	subtarget = 0;
+      if (modifier == EXPAND_STACK_PARM)
+	target = 0;
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
       return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
@@ -8237,14 +8289,14 @@ expand_expr (exp, target, tmode, modifie
 
     case FIX_TRUNC_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
-      if (target == 0)
+      if (target == 0 || modifier == EXPAND_STACK_PARM)
 	target = gen_reg_rtx (mode);
       expand_fix (target, op0, unsignedp);
       return target;
 
     case FLOAT_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
-      if (target == 0)
+      if (target == 0 || modifier == EXPAND_STACK_PARM)
 	target = gen_reg_rtx (mode);
       /* expand_float can't figure out what to do if FROM has VOIDmode.
 	 So give it the correct mode.  With -O, cse will optimize this.  */
@@ -8257,6 +8309,8 @@ expand_expr (exp, target, tmode, modifie
 
     case NEGATE_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      if (modifier == EXPAND_STACK_PARM)
+	target = 0;
       temp = expand_unop (mode,
 			  ! unsignedp && flag_trapv
 			  && (GET_MODE_CLASS(mode) == MODE_INT)
@@ -8267,6 +8321,8 @@ expand_expr (exp, target, tmode, modifie
 
     case ABS_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      if (modifier == EXPAND_STACK_PARM)
+	target = 0;
 
       /* Handle complex values specially.  */
       if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
@@ -8284,7 +8340,9 @@ expand_expr (exp, target, tmode, modifie
     case MAX_EXPR:
     case MIN_EXPR:
       target = original_target;
-      if (target == 0 || ! safe_from_p (target, TREE_OPERAND (exp, 1), 1)
+      if (target == 0
+	  || modifier == EXPAND_STACK_PARM
+	  || ! safe_from_p (target, TREE_OPERAND (exp, 1), 1)
 	  || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
 	  || GET_MODE (target) != mode
 	  || (GET_CODE (target) == REG
@@ -8341,6 +8399,8 @@ expand_expr (exp, target, tmode, modifie
 
     case BIT_NOT_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      if (modifier == EXPAND_STACK_PARM)
+	target = 0;
       temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
       if (temp == 0)
 	abort ();
@@ -8348,6 +8408,8 @@ expand_expr (exp, target, tmode, modifie
 
     case FFS_EXPR:
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+      if (modifier == EXPAND_STACK_PARM)
+	target = 0;
       temp = expand_unop (mode, ffs_optab, op0, target, 1);
       if (temp == 0)
 	abort ();
@@ -8415,6 +8477,8 @@ expand_expr (exp, target, tmode, modifie
     case RROTATE_EXPR:
       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
 	subtarget = 0;
+      if (modifier == EXPAND_STACK_PARM)
+	target = 0;
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
       return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
 			   unsignedp);
@@ -8434,7 +8498,9 @@ expand_expr (exp, target, tmode, modifie
     case UNGT_EXPR:
     case UNGE_EXPR:
     case UNEQ_EXPR:
-      temp = do_store_flag (exp, target, tmode != VOIDmode ? tmode : mode, 0);
+      temp = do_store_flag (exp,
+			    modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
+			    tmode != VOIDmode ? tmode : mode, 0);
       if (temp != 0)
 	return temp;
 
@@ -8483,7 +8549,9 @@ expand_expr (exp, target, tmode, modifie
     case TRUTH_ANDIF_EXPR:
     case TRUTH_ORIF_EXPR:
       if (! ignore
-	  && (target == 0 || ! safe_from_p (target, exp, 1)
+	  && (target == 0
+	      || modifier == EXPAND_STACK_PARM
+	      || ! safe_from_p (target, exp, 1)
 	      /* 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
@@ -8503,6 +8571,8 @@ expand_expr (exp, target, tmode, modifie
       return ignore ? const0_rtx : target;
 
     case TRUTH_NOT_EXPR:
+      if (modifier == EXPAND_STACK_PARM)
+	target = 0;
       op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
       /* The parser is careful to generate TRUTH_NOT_EXPR
 	 only with operands that are always zero or one.  */
@@ -8517,7 +8587,7 @@ expand_expr (exp, target, tmode, modifie
       emit_queue ();
       return expand_expr (TREE_OPERAND (exp, 1),
 			  (ignore ? const0_rtx : target),
-			  VOIDmode, 0);
+			  VOIDmode, modifier);
 
     case COND_EXPR:
       /* If we would have a "singleton" (see below) were it not for a
@@ -8570,6 +8640,8 @@ expand_expr (exp, target, tmode, modifie
 		return const0_rtx;
 	      }
 
+	    if (modifier == EXPAND_STACK_PARM)
+	      target = 0;
 	    op0 = expand_expr (TREE_OPERAND (exp, 0), target, mode, modifier);
 	    if (GET_MODE (op0) == mode)
 	      return op0;
@@ -8610,6 +8682,8 @@ expand_expr (exp, target, tmode, modifie
 
 	if (ignore)
 	  temp = 0;
+	else if (modifier == EXPAND_STACK_PARM)
+	  temp = assign_temp (type, 0, 0, 1);
 	else if (original_target
 		 && (safe_from_p (original_target, TREE_OPERAND (exp, 0), 1)
 		     || (singleton && GET_CODE (original_target) == REG
@@ -8697,7 +8771,8 @@ expand_expr (exp, target, tmode, modifie
 		    || (GET_CODE (temp) == REG
 			&& REGNO (temp) < FIRST_PSEUDO_REGISTER))
 		  temp = gen_reg_rtx (mode);
-		store_expr (singleton, temp, 0);
+		store_expr (singleton, temp,
+			    modifier == EXPAND_STACK_PARM ? 2 : 0);
 	      }
 	    else
 	      expand_expr (singleton,
@@ -8716,11 +8791,11 @@ expand_expr (exp, target, tmode, modifie
 	      store_expr (build (TREE_CODE (binary_op), type,
 				 make_tree (type, temp),
 				 TREE_OPERAND (binary_op, 1)),
-			  temp, 0);
+			  temp, modifier == EXPAND_STACK_PARM ? 2 : 0);
 	    else
 	      store_expr (build1 (TREE_CODE (unary_op), type,
 				  make_tree (type, temp)),
-			  temp, 0);
+			  temp, modifier == EXPAND_STACK_PARM ? 2 : 0);
 	    op1 = op0;
 	  }
 	/* Check for A op 0 ? A : FOO and A op 0 ? FOO : A where OP is any
@@ -8739,11 +8814,13 @@ expand_expr (exp, target, tmode, modifie
 	    if (GET_CODE (temp) == REG
 		&& REGNO (temp) < FIRST_PSEUDO_REGISTER)
 	      temp = gen_reg_rtx (mode);
-	    store_expr (TREE_OPERAND (exp, 1), temp, 0);
+	    store_expr (TREE_OPERAND (exp, 1), temp,
+			modifier == EXPAND_STACK_PARM ? 2 : 0);
 	    jumpif (TREE_OPERAND (exp, 0), op0);
 
 	    start_cleanup_deferral ();
-	    store_expr (TREE_OPERAND (exp, 2), temp, 0);
+	    store_expr (TREE_OPERAND (exp, 2), temp,
+			modifier == EXPAND_STACK_PARM ? 2 : 0);
 	    op1 = op0;
 	  }
 	else if (temp
@@ -8758,11 +8835,13 @@ expand_expr (exp, target, tmode, modifie
 	    if (GET_CODE (temp) == REG
 		&& REGNO (temp) < FIRST_PSEUDO_REGISTER)
 	      temp = gen_reg_rtx (mode);
-	    store_expr (TREE_OPERAND (exp, 2), temp, 0);
+	    store_expr (TREE_OPERAND (exp, 2), temp,
+			modifier == EXPAND_STACK_PARM ? 2 : 0);
 	    jumpifnot (TREE_OPERAND (exp, 0), op0);
 
 	    start_cleanup_deferral ();
-	    store_expr (TREE_OPERAND (exp, 1), temp, 0);
+	    store_expr (TREE_OPERAND (exp, 1), temp,
+			modifier == EXPAND_STACK_PARM ? 2 : 0);
 	    op1 = op0;
 	  }
 	else
@@ -8776,7 +8855,8 @@ expand_expr (exp, target, tmode, modifie
 	       example A ? throw : E  */
 	    if (temp != 0
 		&& TREE_TYPE (TREE_OPERAND (exp, 1)) != void_type_node)
-	      store_expr (TREE_OPERAND (exp, 1), temp, 0);
+	      store_expr (TREE_OPERAND (exp, 1), temp,
+			  modifier == EXPAND_STACK_PARM ? 2 : 0);
 	    else
 	      expand_expr (TREE_OPERAND (exp, 1),
 			   ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
@@ -8788,7 +8868,8 @@ expand_expr (exp, target, tmode, modifie
 	    start_cleanup_deferral ();
 	    if (temp != 0
 		&& TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node)
-	      store_expr (TREE_OPERAND (exp, 2), temp, 0);
+	      store_expr (TREE_OPERAND (exp, 2), temp,
+			  modifier == EXPAND_STACK_PARM ? 2 : 0);
 	    else
 	      expand_expr (TREE_OPERAND (exp, 2),
 			   ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
@@ -8893,7 +8974,7 @@ expand_expr (exp, target, tmode, modifie
 	/* Mark it as expanded.  */
 	TREE_OPERAND (exp, 1) = NULL_TREE;
 
-	store_expr (exp1, target, 0);
+	store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
 
 	expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp));
 
@@ -8978,6 +9059,8 @@ expand_expr (exp, target, tmode, modifie
       return expand_increment (exp, ! ignore, ignore);
 
     case ADDR_EXPR:
+      if (modifier == EXPAND_STACK_PARM)
+	target = 0;
       /* Are we taking the address of a nested function?  */
       if (TREE_CODE (TREE_OPERAND (exp, 0)) == FUNCTION_DECL
 	  && decl_function_context (TREE_OPERAND (exp, 0)) != 0
@@ -9099,7 +9182,8 @@ expand_expr (exp, target, tmode, modifie
 		abort ();
 
 	      emit_block_move (new, op0, expr_size (TREE_OPERAND (exp, 0)),
-			       BLOCK_OP_NORMAL);
+			       (modifier == EXPAND_STACK_PARM
+				? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
 	      op0 = new;
 	    }
 
@@ -9315,6 +9399,8 @@ expand_expr (exp, target, tmode, modifie
   op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
   op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
  binop2:
+  if (modifier == EXPAND_STACK_PARM)
+    target = 0;
   temp = expand_binop (mode, this_optab, op0, op1, target,
 		       unsignedp, OPTAB_LIB_WIDEN);
   if (temp == 0)

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]