diff gcc/calls.c @ 55:77e2b8dfacca gcc-4.4.5

update it from 4.4.3 to 4.5.0
author ryoma <e075725@ie.u-ryukyu.ac.jp>
date Fri, 12 Feb 2010 23:39:51 +0900
parents 855418dad1a3
children 326d9e06c2e3 b7f97abdc517
line wrap: on
line diff
--- a/gcc/calls.c	Sun Feb 07 18:28:00 2010 +0900
+++ b/gcc/calls.c	Fri Feb 12 23:39:51 2010 +0900
@@ -39,6 +39,7 @@
 #include "sbitmap.h"
 #include "langhooks.h"
 #include "target.h"
+#include "debug.h"
 #include "cgraph.h"
 #include "except.h"
 #include "dbgcnt.h"
@@ -166,7 +167,7 @@
    CALL_INSN_FUNCTION_USAGE information.  */
 
 rtx
-prepare_call_address (rtx funexp, rtx static_chain_value,
+prepare_call_address (tree fndecl, rtx funexp, rtx static_chain_value,
 		      rtx *call_fusage, int reg_parm_seen, int sibcallp)
 {
   /* Make a valid memory address and copy constants through pseudo-regs,
@@ -187,11 +188,15 @@
 
   if (static_chain_value != 0)
     {
+      rtx chain;
+
+      gcc_assert (fndecl);
+      chain = targetm.calls.static_chain (fndecl, false);
       static_chain_value = convert_memory_address (Pmode, static_chain_value);
-      emit_move_insn (static_chain_rtx, static_chain_value);
-
-      if (REG_P (static_chain_rtx))
-	use_reg (call_fusage, static_chain_rtx);
+
+      emit_move_insn (chain, static_chain_value);
+      if (REG_P (chain))
+	use_reg (call_fusage, chain);
     }
 
   return funexp;
@@ -238,7 +243,7 @@
    denote registers used by the called function.  */
 
 static void
-emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
+emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNUSED,
 	     tree funtype ATTRIBUTE_UNUSED,
 	     HOST_WIDE_INT stack_size ATTRIBUTE_UNUSED,
 	     HOST_WIDE_INT rounded_stack_size,
@@ -251,10 +256,6 @@
   rtx call_insn;
   int already_popped = 0;
   HOST_WIDE_INT n_popped = RETURN_POPS_ARGS (fndecl, funtype, stack_size);
-#if defined (HAVE_call) && defined (HAVE_call_value)
-  rtx struct_value_size_rtx;
-  struct_value_size_rtx = GEN_INT (struct_value_size);
-#endif
 
 #ifdef CALL_POPS_ARGS
   n_popped += CALL_POPS_ARGS (* args_so_far);
@@ -336,7 +337,7 @@
       else
 	emit_call_insn (GEN_SIBCALL (gen_rtx_MEM (FUNCTION_MODE, funexp),
 				     rounded_stack_size_rtx, next_arg_reg,
-				     struct_value_size_rtx));
+				     GEN_INT (struct_value_size)));
     }
   else
 #endif
@@ -352,7 +353,7 @@
       else
 	emit_call_insn (GEN_CALL (gen_rtx_MEM (FUNCTION_MODE, funexp),
 				  rounded_stack_size_rtx, next_arg_reg,
-				  struct_value_size_rtx));
+				  GEN_INT (struct_value_size)));
     }
   else
 #endif
@@ -376,19 +377,8 @@
   if (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
     RTL_LOOPING_CONST_OR_PURE_CALL_P (call_insn) = 1;
 
-  /* If this call can't throw, attach a REG_EH_REGION reg note to that
-     effect.  */
-  if (ecf_flags & ECF_NOTHROW)
-    add_reg_note (call_insn, REG_EH_REGION, const0_rtx);
-  else
-    {
-      int rn = lookup_expr_eh_region (fntree);
-
-      /* If rn < 0, then either (1) tree-ssa not used or (2) doesn't
-	 throw, which we already took care of.  */
-      if (rn > 0)
-	add_reg_note (call_insn, REG_EH_REGION, GEN_INT (rn));
-    }
+  /* Create a nothrow REG_EH_REGION note, if needed.  */
+  make_reg_eh_region_note (call_insn, ecf_flags, 0);
 
   if (ecf_flags & ECF_NORETURN)
     add_reg_note (call_insn, REG_NORETURN, const0_rtx);
@@ -401,6 +391,11 @@
 
   SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0);
 
+  /* Record debug information for virtual calls.  */
+  if (flag_enable_icf_debug && fndecl == NULL)
+    (*debug_hooks->virtual_call_token) (CALL_EXPR_FN (fntree),
+                                        INSN_UID (call_insn));
+
   /* Restore this now, so that we do defer pops for this call's args
      if the context of the call as a whole permits.  */
   inhibit_defer_pop = old_inhibit_defer_pop;
@@ -590,12 +585,9 @@
 flags_from_decl_or_type (const_tree exp)
 {
   int flags = 0;
-  const_tree type = exp;
 
   if (DECL_P (exp))
     {
-      type = TREE_TYPE (exp);
-
       /* The function exp may have the `malloc' attribute.  */
       if (DECL_IS_MALLOC (exp))
 	flags |= ECF_MALLOC;
@@ -907,7 +899,7 @@
 }
 
 /* Fill in ARGS_SIZE and ARGS array based on the parameters found in
-   CALL_EXPR EXP.  
+   CALL_EXPR EXP.
 
    NUM_ACTUALS is the total number of parameters.
 
@@ -949,6 +941,7 @@
 				 int *must_preallocate, int *ecf_flags,
 				 bool *may_tailcall, bool call_from_thunk_p)
 {
+  location_t loc = EXPR_LOCATION (exp);
   /* 1 if scanning parms front to back, -1 if scanning back to front.  */
   int inc;
 
@@ -1054,6 +1047,7 @@
 	      || (callee_copies
 		  && !TREE_ADDRESSABLE (type)
 		  && (base = get_base_address (args[i].tree_value))
+		  && TREE_CODE (base) != SSA_NAME
 		  && (!DECL_P (base) || MEM_P (DECL_RTL (base)))))
 	    {
 	      /* We can't use sibcalls if a callee-copied argument is
@@ -1061,7 +1055,8 @@
 	      if (!call_from_thunk_p && DECL_P (base) && !TREE_STATIC (base))
 		*may_tailcall = false;
 
-	      args[i].tree_value = build_fold_addr_expr (args[i].tree_value);
+	      args[i].tree_value = build_fold_addr_expr_loc (loc,
+							 args[i].tree_value);
 	      type = TREE_TYPE (args[i].tree_value);
 
 	      if (*ecf_flags & ECF_CONST)
@@ -1113,19 +1108,15 @@
 		*ecf_flags &= ~(ECF_PURE | ECF_LOOPING_CONST_OR_PURE);
 
 	      args[i].tree_value
-		= build_fold_addr_expr (make_tree (type, copy));
+		= build_fold_addr_expr_loc (loc, make_tree (type, copy));
 	      type = TREE_TYPE (args[i].tree_value);
 	      *may_tailcall = false;
 	    }
 	}
 
-      mode = TYPE_MODE (type);
       unsignedp = TYPE_UNSIGNED (type);
-
-      if (targetm.calls.promote_function_args (fndecl
-					       ? TREE_TYPE (fndecl)
-					       : fntype))
-	mode = promote_mode (type, mode, &unsignedp, 1);
+      mode = promote_function_mode (type, TYPE_MODE (type), &unsignedp,
+				    fndecl ? TREE_TYPE (fndecl) : fntype, 0);
 
       args[i].unsignedp = unsignedp;
       args[i].mode = mode;
@@ -1305,29 +1296,33 @@
 
   for (i = 0; i < num_actuals; i++)
     {
+      tree type;
       enum machine_mode mode;
 
       if (TREE_CODE (args[i].tree_value) != CALL_EXPR)
 	continue;
 
       /* If this is an addressable type, we cannot pre-evaluate it.  */
-      gcc_assert (!TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)));
+      type = TREE_TYPE (args[i].tree_value);
+      gcc_assert (!TREE_ADDRESSABLE (type));
 
       args[i].initial_value = args[i].value
 	= expand_normal (args[i].tree_value);
 
-      mode = TYPE_MODE (TREE_TYPE (args[i].tree_value));
+      mode = TYPE_MODE (type);
       if (mode != args[i].mode)
 	{
+	  int unsignedp = args[i].unsignedp;
 	  args[i].value
 	    = convert_modes (args[i].mode, mode,
 			     args[i].value, args[i].unsignedp);
-#if defined(PROMOTE_FUNCTION_MODE) && !defined(PROMOTE_MODE)
+
 	  /* CSE will replace this only if it contains args[i].value
 	     pseudo, so convert it down to the declared mode using
 	     a SUBREG.  */
 	  if (REG_P (args[i].value)
-	      && GET_MODE_CLASS (args[i].mode) == MODE_INT)
+	      && GET_MODE_CLASS (args[i].mode) == MODE_INT
+	      && promote_mode (type, mode, &unsignedp) != args[i].mode)
 	    {
 	      args[i].initial_value
 		= gen_lowpart_SUBREG (mode, args[i].value);
@@ -1335,7 +1330,6 @@
 	      SUBREG_PROMOTED_UNSIGNED_SET (args[i].initial_value,
 					    args[i].unsignedp);
 	    }
-#endif
 	}
     }
 }
@@ -1345,7 +1339,7 @@
    compute and return the final value for MUST_PREALLOCATE.  */
 
 static int
-finalize_must_preallocate (int must_preallocate, int num_actuals, 
+finalize_must_preallocate (int must_preallocate, int num_actuals,
 			   struct arg_data *args, struct args_size *args_size)
 {
   /* See if we have or want to preallocate stack space.
@@ -1430,7 +1424,7 @@
 	      && args[i].partial == 0)
 	    continue;
 
-	  if (GET_CODE (offset) == CONST_INT)
+	  if (CONST_INT_P (offset))
 	    addr = plus_constant (arg_reg, INTVAL (offset));
 	  else
 	    addr = gen_rtx_PLUS (Pmode, arg_reg, offset);
@@ -1457,14 +1451,14 @@
 	  boundary = args[i].locate.boundary;
 	  if (args[i].locate.where_pad != downward)
 	    align = boundary;
-	  else if (GET_CODE (offset) == CONST_INT)
+	  else if (CONST_INT_P (offset))
 	    {
 	      align = INTVAL (offset) * BITS_PER_UNIT | boundary;
 	      align = align & -align;
 	    }
 	  set_mem_align (args[i].stack, align);
 
-	  if (GET_CODE (slot_offset) == CONST_INT)
+	  if (CONST_INT_P (slot_offset))
 	    addr = plus_constant (arg_reg, INTVAL (slot_offset));
 	  else
 	    addr = gen_rtx_PLUS (Pmode, arg_reg, slot_offset);
@@ -1548,7 +1542,7 @@
     i = 0;
   else if (GET_CODE (addr) == PLUS
 	   && XEXP (addr, 0) == crtl->args.internal_arg_pointer
-	   && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+	   && CONST_INT_P (XEXP (addr, 1)))
     i = INTVAL (XEXP (addr, 1));
   /* Return true for arg pointer based indexed addressing.  */
   else if (GET_CODE (addr) == PLUS
@@ -1925,6 +1919,7 @@
   /* Data type of the function.  */
   tree funtype;
   tree type_arg_types;
+  tree rettype;
   /* Declaration of the function being called,
      or 0 if the function is computed (not known by name).  */
   tree fndecl = 0;
@@ -2020,7 +2015,6 @@
   int old_stack_pointer_delta = 0;
 
   rtx call_fusage;
-  tree p = CALL_EXPR_FN (exp);
   tree addr = CALL_EXPR_FN (exp);
   int i;
   /* The alignment of the stack, in bits.  */
@@ -2043,15 +2037,16 @@
     }
   else
     {
-      fntype = TREE_TYPE (TREE_TYPE (p));
+      fntype = TREE_TYPE (TREE_TYPE (addr));
       flags |= flags_from_decl_or_type (fntype);
     }
+  rettype = TREE_TYPE (exp);
 
   struct_value = targetm.calls.struct_value_rtx (fntype, 0);
 
   /* Warn if this value is an aggregate type,
      regardless of which calling convention we are using for it.  */
-  if (AGGREGATE_TYPE_P (TREE_TYPE (exp)))
+  if (AGGREGATE_TYPE_P (rettype))
     warning (OPT_Waggregate_return, "function call has aggregate value");
 
   /* If the result of a non looping pure or const function call is
@@ -2061,7 +2056,7 @@
   if ((flags & (ECF_CONST | ECF_PURE))
       && (!(flags & ECF_LOOPING_CONST_OR_PURE))
       && (ignore || target == const0_rtx
-	  || TYPE_MODE (TREE_TYPE (exp)) == VOIDmode))
+	  || TYPE_MODE (rettype) == VOIDmode))
     {
       bool volatilep = false;
       tree arg;
@@ -2104,7 +2099,7 @@
       }
 #else /* not PCC_STATIC_STRUCT_RETURN */
       {
-	struct_value_size = int_size_in_bytes (TREE_TYPE (exp));
+	struct_value_size = int_size_in_bytes (rettype);
 
 	if (target && MEM_P (target) && CALL_EXPR_RETURN_SLOT_OPT (exp))
 	  structure_value_addr = XEXP (target, 0);
@@ -2113,7 +2108,7 @@
 	    /* For variable-sized objects, we must be called with a target
 	       specified.  If we were to allocate space on the stack here,
 	       we would have no way of knowing when to free it.  */
-	    rtx d = assign_temp (TREE_TYPE (exp), 0, 1, 1);
+	    rtx d = assign_temp (rettype, 0, 1, 1);
 
 	    mark_temp_addr_taken (d);
 	    structure_value_addr = XEXP (d, 0);
@@ -2284,7 +2279,6 @@
   if (currently_expanding_call++ != 0
       || !flag_optimize_sibling_calls
       || args_size.var
-      || lookup_expr_eh_region (exp) >= 0
       || dbg_cnt (tail_call) == false)
     try_tail_call = 0;
 
@@ -2343,17 +2337,17 @@
       tree caller_res = DECL_RESULT (current_function_decl);
 
       caller_unsignedp = TYPE_UNSIGNED (TREE_TYPE (caller_res));
-      caller_mode = caller_promoted_mode = DECL_MODE (caller_res);
+      caller_mode = DECL_MODE (caller_res);
       callee_unsignedp = TYPE_UNSIGNED (TREE_TYPE (funtype));
-      callee_mode = callee_promoted_mode = TYPE_MODE (TREE_TYPE (funtype));
-      if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl)))
-	caller_promoted_mode
-	  = promote_mode (TREE_TYPE (caller_res), caller_mode,
-			  &caller_unsignedp, 1);
-      if (targetm.calls.promote_function_return (funtype))
-	callee_promoted_mode
-	  = promote_mode (TREE_TYPE (funtype), callee_mode,
-			  &callee_unsignedp, 1);
+      callee_mode = TYPE_MODE (TREE_TYPE (funtype));
+      caller_promoted_mode
+	= promote_function_mode (TREE_TYPE (caller_res), caller_mode,
+				 &caller_unsignedp,
+				 TREE_TYPE (current_function_decl), 1);
+      callee_promoted_mode
+	= promote_function_mode (TREE_TYPE (funtype), callee_mode,
+				 &callee_unsignedp,
+				 funtype, 1);
       if (caller_mode != VOIDmode
 	  && (caller_promoted_mode != callee_promoted_mode
 	      || ((caller_mode != caller_promoted_mode
@@ -2691,14 +2685,14 @@
 
       /* Figure out the register where the value, if any, will come back.  */
       valreg = 0;
-      if (TYPE_MODE (TREE_TYPE (exp)) != VOIDmode
+      if (TYPE_MODE (rettype) != VOIDmode
 	  && ! structure_value_addr)
 	{
 	  if (pcc_struct_value)
-	    valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)),
+	    valreg = hard_function_value (build_pointer_type (rettype),
 					  fndecl, NULL, (pass == 0));
 	  else
-	    valreg = hard_function_value (TREE_TYPE (exp), fndecl, fntype,
+	    valreg = hard_function_value (rettype, fndecl, fntype,
 					  (pass == 0));
 
 	  /* If VALREG is a PARALLEL whose first member has a zero
@@ -2816,7 +2810,7 @@
 	}
 
       after_args = get_last_insn ();
-      funexp = prepare_call_address (funexp, static_chain_value,
+      funexp = prepare_call_address (fndecl, funexp, static_chain_value,
 				     &call_fusage, reg_parm_seen, pass == 0);
 
       load_register_parameters (args, num_actuals, &call_fusage, flags,
@@ -2863,12 +2857,12 @@
 	 group load/store machinery below.  */
       if (!structure_value_addr
 	  && !pcc_struct_value
-	  && TYPE_MODE (TREE_TYPE (exp)) != BLKmode
-	  && targetm.calls.return_in_msb (TREE_TYPE (exp)))
+	  && TYPE_MODE (rettype) != BLKmode
+	  && targetm.calls.return_in_msb (rettype))
 	{
-	  if (shift_return_value (TYPE_MODE (TREE_TYPE (exp)), false, valreg))
+	  if (shift_return_value (TYPE_MODE (rettype), false, valreg))
 	    sibcall_failure = 1;
-	  valreg = gen_rtx_REG (TYPE_MODE (TREE_TYPE (exp)), REGNO (valreg));
+	  valreg = gen_rtx_REG (TYPE_MODE (rettype), REGNO (valreg));
 	}
 
       if (pass && (flags & ECF_MALLOC))
@@ -2877,7 +2871,7 @@
 	  rtx last, insns;
 
 	  /* The return value from a malloc-like function is a pointer.  */
-	  if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
+	  if (TREE_CODE (rettype) == POINTER_TYPE)
 	    mark_reg_pointer (temp, BIGGEST_ALIGNMENT);
 
 	  emit_move_insn (temp, valreg);
@@ -2927,7 +2921,7 @@
 
       /* If value type not void, return an rtx for the value.  */
 
-      if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode
+      if (TYPE_MODE (rettype) == VOIDmode
 	  || ignore)
 	target = const0_rtx;
       else if (structure_value_addr)
@@ -2935,10 +2929,10 @@
 	  if (target == 0 || !MEM_P (target))
 	    {
 	      target
-		= gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)),
-			       memory_address (TYPE_MODE (TREE_TYPE (exp)),
+		= gen_rtx_MEM (TYPE_MODE (rettype),
+			       memory_address (TYPE_MODE (rettype),
 					       structure_value_addr));
-	      set_mem_attributes (target, exp, 1);
+	      set_mem_attributes (target, rettype, 1);
 	    }
 	}
       else if (pcc_struct_value)
@@ -2946,9 +2940,9 @@
 	  /* This is the special C++ case where we need to
 	     know what the true target was.  We take care to
 	     never use this value more than once in one expression.  */
-	  target = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)),
+	  target = gen_rtx_MEM (TYPE_MODE (rettype),
 				copy_to_reg (valreg));
-	  set_mem_attributes (target, exp, 1);
+	  set_mem_attributes (target, rettype, 1);
 	}
       /* Handle calls that return values in multiple non-contiguous locations.
 	 The Irix 6 ABI has examples of this.  */
@@ -2957,22 +2951,22 @@
 	  if (target == 0)
 	    {
 	      /* This will only be assigned once, so it can be readonly.  */
-	      tree nt = build_qualified_type (TREE_TYPE (exp),
-					      (TYPE_QUALS (TREE_TYPE (exp))
+	      tree nt = build_qualified_type (rettype,
+					      (TYPE_QUALS (rettype)
 					       | TYPE_QUAL_CONST));
 
 	      target = assign_temp (nt, 0, 1, 1);
 	    }
 
 	  if (! rtx_equal_p (target, valreg))
-	    emit_group_store (target, valreg, TREE_TYPE (exp),
-			      int_size_in_bytes (TREE_TYPE (exp)));
+	    emit_group_store (target, valreg, rettype,
+			      int_size_in_bytes (rettype));
 
 	  /* We can not support sibling calls for this case.  */
 	  sibcall_failure = 1;
 	}
       else if (target
-	       && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp))
+	       && GET_MODE (target) == TYPE_MODE (rettype)
 	       && GET_MODE (target) == GET_MODE (valreg))
 	{
 	  bool may_overlap = false;
@@ -3017,12 +3011,12 @@
 		sibcall_failure = 1;
 	    }
 	}
-      else if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
+      else if (TYPE_MODE (rettype) == BLKmode)
 	{
 	  rtx val = valreg;
 	  if (GET_MODE (val) != BLKmode)
 	    val = avoid_likely_spilled_reg (val);
-	  target = copy_blkmode_from_reg (target, val, TREE_TYPE (exp));
+	  target = copy_blkmode_from_reg (target, val, rettype);
 
 	  /* We can not support sibling calls for this case.  */
 	  sibcall_failure = 1;
@@ -3030,38 +3024,37 @@
       else
 	target = copy_to_reg (avoid_likely_spilled_reg (valreg));
 
-      if (targetm.calls.promote_function_return(funtype))
+      /* If we promoted this return value, make the proper SUBREG.
+         TARGET might be const0_rtx here, so be careful.  */
+      if (REG_P (target)
+	  && TYPE_MODE (rettype) != BLKmode
+	  && GET_MODE (target) != TYPE_MODE (rettype))
 	{
-	  /* If we promoted this return value, make the proper SUBREG.
-	     TARGET might be const0_rtx here, so be careful.  */
-	  if (REG_P (target)
-	      && TYPE_MODE (TREE_TYPE (exp)) != BLKmode
-	      && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
+	  tree type = rettype;
+	  int unsignedp = TYPE_UNSIGNED (type);
+	  int offset = 0;
+	  enum machine_mode pmode;
+
+	  /* Ensure we promote as expected, and get the new unsignedness.  */
+	  pmode = promote_function_mode (type, TYPE_MODE (type), &unsignedp,
+					 funtype, 1);
+	  gcc_assert (GET_MODE (target) == pmode);
+
+	  if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
+	      && (GET_MODE_SIZE (GET_MODE (target))
+		  > GET_MODE_SIZE (TYPE_MODE (type))))
 	    {
-	      tree type = TREE_TYPE (exp);
-	      int unsignedp = TYPE_UNSIGNED (type);
-	      int offset = 0;
-	      enum machine_mode pmode;
-
-	      pmode = promote_mode (type, TYPE_MODE (type), &unsignedp, 1);
-	      /* If we don't promote as expected, something is wrong.  */
-	      gcc_assert (GET_MODE (target) == pmode);
-
-	      if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
-		  && (GET_MODE_SIZE (GET_MODE (target))
-		      > GET_MODE_SIZE (TYPE_MODE (type))))
-		{
-		  offset = GET_MODE_SIZE (GET_MODE (target))
-		    - GET_MODE_SIZE (TYPE_MODE (type));
-		  if (! BYTES_BIG_ENDIAN)
-		    offset = (offset / UNITS_PER_WORD) * UNITS_PER_WORD;
-		  else if (! WORDS_BIG_ENDIAN)
-		    offset %= UNITS_PER_WORD;
-		}
-	      target = gen_rtx_SUBREG (TYPE_MODE (type), target, offset);
-	      SUBREG_PROMOTED_VAR_P (target) = 1;
-	      SUBREG_PROMOTED_UNSIGNED_SET (target, unsignedp);
+	      offset = GET_MODE_SIZE (GET_MODE (target))
+	        - GET_MODE_SIZE (TYPE_MODE (type));
+	      if (! BYTES_BIG_ENDIAN)
+	        offset = (offset / UNITS_PER_WORD) * UNITS_PER_WORD;
+	      else if (! WORDS_BIG_ENDIAN)
+	        offset %= UNITS_PER_WORD;
 	    }
+
+	  target = gen_rtx_SUBREG (TYPE_MODE (type), target, offset);
+	  SUBREG_PROMOTED_VAR_P (target) = 1;
+	  SUBREG_PROMOTED_UNSIGNED_SET (target, unsignedp);
 	}
 
       /* If size of args is variable or this was a constructor call for a stack
@@ -3447,7 +3440,7 @@
   for (; count < nargs; count++)
     {
       rtx val = va_arg (p, rtx);
-      enum machine_mode mode = va_arg (p, enum machine_mode);
+      enum machine_mode mode = (enum machine_mode) va_arg (p, int);
 
       /* We cannot convert the arg value to the mode the library wants here;
 	 must do it earlier where we know the signedness of the arg.  */
@@ -3637,6 +3630,7 @@
       rtx val = argvec[argnum].value;
       rtx reg = argvec[argnum].reg;
       int partial = argvec[argnum].partial;
+      unsigned int parm_align = argvec[argnum].locate.boundary;
       int lower_bound = 0, upper_bound = 0, i;
 
       if (! (reg != 0 && partial == 0))
@@ -3698,7 +3692,7 @@
 		}
 	    }
 
-	  emit_push_insn (val, mode, NULL_TREE, NULL_RTX, PARM_BOUNDARY,
+	  emit_push_insn (val, mode, NULL_TREE, NULL_RTX, parm_align,
 			  partial, reg, 0, argblock,
 			  GEN_INT (argvec[argnum].locate.offset.constant),
 			  reg_parm_stack_space,
@@ -3747,7 +3741,7 @@
   else
     argnum = 0;
 
-  fun = prepare_call_address (fun, NULL, &call_fusage, 0, 0);
+  fun = prepare_call_address (NULL, fun, NULL, &call_fusage, 0, 0);
 
   /* Now load any reg parms into their regs.  */
 
@@ -3806,7 +3800,7 @@
      cse'ing of library calls could delete a call and leave the pop.  */
   NO_DEFER_POP;
   valreg = (mem_value == 0 && outmode != VOIDmode
-	    ? hard_libcall_value (outmode) : NULL_RTX);
+	    ? hard_libcall_value (outmode, orgfun) : NULL_RTX);
 
   /* Stack must be properly aligned now.  */
   gcc_assert (!(stack_pointer_delta
@@ -3875,15 +3869,14 @@
 	}
       else
 	{
-	  /* Convert to the proper mode if PROMOTE_MODE has been active.  */
+	  /* Convert to the proper mode if a promotion has been active.  */
 	  if (GET_MODE (valreg) != outmode)
 	    {
 	      int unsignedp = TYPE_UNSIGNED (tfom);
 
-	      gcc_assert (targetm.calls.promote_function_return (tfom));
-	      gcc_assert (promote_mode (tfom, outmode, &unsignedp, 0)
+	      gcc_assert (promote_function_mode (tfom, outmode, &unsignedp,
+						 fndecl ? TREE_TYPE (fndecl) : fntype, 1)
 			  == GET_MODE (valreg));
-
 	      valreg = convert_modes (outmode, GET_MODE (valreg), valreg, 0);
 	    }
 
@@ -4235,7 +4228,8 @@
 		    - int_size_in_bytes (TREE_TYPE (pval))
 		    + partial);
 	  size_rtx = expand_expr (size_in_bytes (TREE_TYPE (pval)),
-				  NULL_RTX, TYPE_MODE (sizetype), 0);
+				  NULL_RTX, TYPE_MODE (sizetype),
+				  EXPAND_NORMAL);
 	}
 
       parm_align = arg->locate.boundary;
@@ -4264,7 +4258,7 @@
 	      || (GET_CODE (XEXP (x, 0)) == PLUS
 		  && XEXP (XEXP (x, 0), 0) ==
 		     crtl->args.internal_arg_pointer
-		  && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
+		  && CONST_INT_P (XEXP (XEXP (x, 0), 1))))
 	    {
 	      if (XEXP (x, 0) != crtl->args.internal_arg_pointer)
 		i = INTVAL (XEXP (XEXP (x, 0), 1));
@@ -4272,7 +4266,7 @@
 	      /* expand_call should ensure this.  */
 	      gcc_assert (!arg->locate.offset.var
 			  && arg->locate.size.var == 0
-			  && GET_CODE (size_rtx) == CONST_INT);
+			  && CONST_INT_P (size_rtx));
 
 	      if (arg->locate.offset.constant > i)
 		{