view gcc/cbc-goto.h @ 60:bd49c42ec43e

remove unnecessary files
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 15 Feb 2010 17:39:45 +0900
parents 3aaf117db171
children
line wrap: on
line source


static void
preexpand_argument_expr (struct arg_data *, int);

static void
determine_order(int *, int);

static int
expand_one_arg_push (struct arg_data *, rtx, int, int, int);

static void
push_overlaps(struct arg_data *, int);

static int
check_frame_offset(rtx);


static rtx
expand_cbc_goto (tree exp, rtx target, tree fndecl, tree funtype, tree fntype,
                 tree addr,
                 int ignore,
                 int flags,
                 int num_actuals,
                 struct arg_data *args,
                 struct args_size *args_size,
                 CUMULATIVE_ARGS args_so_far,
                 rtx old_stack_level,
                 int reg_parm_stack_space,
                 int old_pending_adj,
                 unsigned HOST_WIDE_INT preferred_stack_boundary,
                 unsigned HOST_WIDE_INT preferred_unit_stack_boundary,
                 rtx structure_value_addr,
                 //int structure_value_addr_parm,
                 int old_inhibit_defer_pop
                 )
{

  /* folowing variables is just copied from expand_call.  */

  int pass = 0;
  int i;
#ifdef REG_PARM_STACK_SPACE
  /* Define the boundary of the register parm stack space that needs to be
     saved, if any.  */
#endif
  rtx funexp;
  rtx valreg;
  struct args_size adjusted_args_size;
  int unadjusted_args_size;
  int reg_parm_seen;
  rtx static_chain_value;
  int old_stack_allocated;
  int old_stack_pointer_delta = 0;
  int old_stack_arg_under_construction = 0;
  rtx call_fusage;
  char *stack_usage_map_buf = NULL;
  rtx argblock = 0;
  HOST_WIDE_INT struct_value_size = 0;
  int pcc_struct_value = 0;
  int initial_highest_arg_in_use = highest_outgoing_arg_in_use;
  char *initial_stack_usage_map = stack_usage_map;
  rtx tail_call_insns = NULL_RTX;


  int *store_order;


  int sibcall_failure = 0;
  /* We want to emit any pending stack adjustments before the tail
     recursion "call".  That way we know any adjustment after the tail
     recursion call can be ignored if we indeed use the tail
     call expansion.  */
  int save_pending_stack_adjust = 0;
  int save_stack_pointer_delta = 0;
  rtx insns;
  rtx before_call, next_arg_reg;

  /* State variables we need to save and restore between
     iterations.  */
  save_pending_stack_adjust = pending_stack_adjust;
  save_stack_pointer_delta = stack_pointer_delta;
  flags |= ECF_SIBCALL;

  /* Other state variables that we must reinitialize each time
     through the loop (that are not initialized by the loop itself).  */
  argblock = 0;
  call_fusage = 0;

  /* Start a new sequence for the normal call case.

     From this point on, if the sibling call fails, we want to set
     sibcall_failure instead of continuing the loop.  */
  start_sequence ();

  /* Don't let pending stack adjusts add up to too much.
     Also, do all pending adjustments now if there is any chance
     this might be a call to alloca or if we are expanding a sibling
     call sequence or if we are calling a function that is to return
     with stack pointer depressed.
     Also do the adjustments before a throwing call, otherwise
     exception handling can fail; PR 19225. */
  if (pending_stack_adjust >= 32
      || (pending_stack_adjust > 0
          && (flags & ECF_MAY_BE_ALLOCA))
      || (pending_stack_adjust > 0
          && flag_exceptions && !(flags & ECF_NOTHROW))
      || pass == 0)
    do_pending_stack_adjust ();


  if (pass == 0 && crtl->stack_protect_guard)
    stack_protect_epilogue ();

  adjusted_args_size = *args_size;
  /* Compute the actual size of the argument block required.  The variable
     and constant sizes must be combined, the size may have to be rounded,
     and there may be a minimum required size.  When generating a sibcall
     pattern, do not round up, since we'll be re-using whatever space our
     caller provided.  */
  unadjusted_args_size
    = compute_argument_block_size (reg_parm_stack_space,
                                   &adjusted_args_size,
                                   fndecl, fntype,
                                   (pass == 0 ? 0
                                    : preferred_stack_boundary));

  old_stack_allocated = stack_pointer_delta - pending_stack_adjust;

  argblock = crtl->args.internal_arg_pointer;

  argblock
#ifdef STACK_GROWS_DOWNWARD
    = plus_constant (argblock, crtl->args.pretend_args_size);
#else
  = plus_constant (argblock, -crtl->args.pretend_args_size);
#endif


  stored_args_map = sbitmap_alloc (args_size->constant);
  sbitmap_zero (stored_args_map);


  if (ACCUMULATE_OUTGOING_ARGS)
    {
      /* The save/restore code in store_one_arg handles all
         cases except one: a constructor call (including a C
         function returning a BLKmode struct) to initialize
         an argument.  */
      if (stack_arg_under_construction)
        {
          rtx push_size
            = GEN_INT (adjusted_args_size.constant
                       + (OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype
                                                          : TREE_TYPE (fndecl))) ? 0
                          : reg_parm_stack_space));
          if (old_stack_level == 0)
            {
              emit_stack_save (SAVE_BLOCK, &old_stack_level,
                               NULL_RTX);
              old_stack_pointer_delta = stack_pointer_delta;
              old_pending_adj = pending_stack_adjust;
              pending_stack_adjust = 0;
              /* stack_arg_under_construction says whether a stack
                 arg is being constructed at the old stack level.
                 Pushing the stack gets a clean outgoing argument
                 block.  */
              old_stack_arg_under_construction
                = stack_arg_under_construction;
              stack_arg_under_construction = 0;
              /* Make a new map for the new argument list.  */
              if (stack_usage_map_buf)
                free (stack_usage_map_buf);
              stack_usage_map_buf = XNEWVEC (char, highest_outgoing_arg_in_use);
              stack_usage_map = stack_usage_map_buf;
              memset (stack_usage_map, 0, highest_outgoing_arg_in_use);
              highest_outgoing_arg_in_use = 0;
            }
          allocate_dynamic_stack_space (push_size, NULL_RTX,
                                        BITS_PER_UNIT);
        }

      /* If argument evaluation might modify the stack pointer,
         copy the address of the argument list to a register.  */
      for (i = 0; i < num_actuals; i++)
        if (args[i].pass_on_stack)
          {
            argblock = copy_addr_to_reg (argblock);
            break;
          }
    }

  compute_argument_addresses (args, argblock, num_actuals);

  /* in the case that
     a function goto codesegment.
     adjust stack space.  */
  if ( !CbC_IS_CODE_SEGMENT(TREE_TYPE(current_function_decl)) )
    //if ( !(current_function_decl&&CbC_IS_CODE_SEGMENT(current_function_decl)) )
    {
      HOST_WIDE_INT padding;
      padding = CbC_PRETENDED_STACK_SIZE -
        (crtl->args.size - crtl->args.pretend_args_size);
      if (0&&padding > 0)
        anti_adjust_stack (GEN_INT (padding));
    }

  /* Now that the stack is properly aligned, pops can't safely
     be deferred during the evaluation of the arguments.  */
  NO_DEFER_POP;

  funexp = rtx_for_function_call (fndecl, addr);

  /* Figure out the register where the value, if any, will come back.  */
  valreg = 0;


  /* Precompute all register parameters.  It isn't safe to compute anything
     once we have started filling any specific hard regs.  */
  precompute_register_parameters (num_actuals, args, &reg_parm_seen);

  if (CALL_EXPR_STATIC_CHAIN (exp))
    static_chain_value = expand_normal (CALL_EXPR_STATIC_CHAIN (exp));
  else
    static_chain_value = 0;


  /* parallel assignment  */
  store_order = alloca (num_actuals * sizeof (int));
  memset (store_order, 0, num_actuals * sizeof (int));

  /* fill the arg[i]->exprs. */
  for (i = 0; i < num_actuals; i++)
    {
      if (args[i].reg == 0 || args[i].pass_on_stack)
        {
          preexpand_argument_expr (&args[i],
                                   adjusted_args_size.var != 0);
        }
    }


  /* push overlapped argument to stack.  */
  push_overlaps(args, num_actuals);

  /* determine ordering to store arguments.
     and generate RTL that store some variable temporary, if it needed.*/
  /* now... this function do nothing.  */
  determine_order(store_order, num_actuals);

  /* push arguments in the order .  */
  for (i = 0; i < num_actuals; i++)
    {
      if (args[store_order[i]].reg == 0
          || args[store_order[i]].pass_on_stack
          || args[store_order[i]].partial!=0 )
        {
          expand_one_arg_push (&args[store_order[i]], argblock, flags,
                               adjusted_args_size.var != 0,
                               reg_parm_stack_space);
        }
    }


  /* If register arguments require space on the stack and stack space
     was not preallocated, allocate stack space here for arguments
     passed in registers.  */
#ifdef OUTGOING_REG_PARM_STACK_SPACE
  //if (!ACCUMULATE_OUTGOING_ARGS
  //&& must_preallocate == 0 && reg_parm_stack_space > 0)
  //anti_adjust_stack (GEN_INT (reg_parm_stack_space));
#endif

  /*   */
  funexp = prepare_call_address (fndecl, funexp, static_chain_value,
                                 &call_fusage, reg_parm_seen, pass == 0);

  /* store args into register.  */
  load_register_parameters (args, num_actuals, &call_fusage, flags,
                            //pass == 0, &sibcall_failure);
                            0, NULL);

  /* Save a pointer to the last insn before the call, so that we can
     later safely search backwards to find the CALL_INSN.  */
  before_call = get_last_insn ();

  /* Set up next argument register.  For sibling calls on machines
     with register windows this should be the incoming register.  */
#ifdef FUNCTION_INCOMING_ARG
  if (pass == 0)
    next_arg_reg = FUNCTION_INCOMING_ARG (args_so_far, VOIDmode,
                                          void_type_node, 1);
  else
#endif
    next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode,
                                 void_type_node, 1);

  /* All arguments and registers used for the call must be set up by
     now!  */

  /* Stack must be properly aligned now.  */
  gcc_assert (!pass
              || !(stack_pointer_delta % preferred_unit_stack_boundary));
#if 0
  /* store environment.  */
  if ( env_tree!=NULL )
    {
      emit_insn (gen_rtx_CLOBBER (VOIDmode,
                                  gen_rtx_MEM (BLKmode,
                                               hard_frame_pointer_rtx)));
      emit_move_insn (hard_frame_pointer_rtx, env_rtx);
      emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
      //pop_temp_slots ();

      emit_indirect_jump (funexp);
    }
#endif
  if (GET_CODE (funexp) != SYMBOL_REF)
    {
      push_temp_slots();
      preserve_temp_slots(funexp);
      /* Generate the actual call instruction.  */
      emit_call_1 (funexp, exp, fndecl, funtype, unadjusted_args_size,
                   adjusted_args_size.constant, struct_value_size,
                   //next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
                   next_arg_reg, valreg, 0, call_fusage,
                   flags, & args_so_far);
      pop_temp_slots();
    }
  else
    {

      /* Generate the actual call instruction.  */
      emit_call_1 (funexp, exp, fndecl, funtype, unadjusted_args_size,
                   adjusted_args_size.constant, struct_value_size,
                   //next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
                   next_arg_reg, valreg, 0, call_fusage,
                   flags, & args_so_far);
    }

  /* If a non-BLKmode value is returned at the most significant end
     of a register, shift the register right by the appropriate amount
     and update VALREG accordingly.  BLKmode values are handled by the
     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)))
    {
      if (shift_return_value (TYPE_MODE (TREE_TYPE (exp)), false, valreg))
        sibcall_failure = 1;
      valreg = gen_rtx_REG (TYPE_MODE (TREE_TYPE (exp)), REGNO (valreg));
    }


  /* For calls to `setjmp', etc., inform flow.c it should complain
     if nonvolatile values are live.  For functions that cannot return,
     inform flow that control does not fall through.  */

  if ((flags & ECF_NORETURN) || pass == 0)
    {
      /* The barrier must be emitted
         immediately after the CALL_INSN.  Some ports emit more
         than just a CALL_INSN above, so we must search for it here.  */

      rtx last = get_last_insn ();
      while (!CALL_P (last))
        {
          last = PREV_INSN (last);
          /* There was no CALL_INSN?  */
          gcc_assert (last != before_call);
        }

      emit_barrier_after (last);

      /* Stack adjustments after a noreturn call are dead code.
         However when NO_DEFER_POP is in effect, we must preserve
         stack_pointer_delta.  */
      if (inhibit_defer_pop == 0)
        {
          stack_pointer_delta = old_stack_allocated;
          pending_stack_adjust = 0;
        }
    }

  /* If value type not void, return an rtx for the value.  */

  if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode
      || ignore)
    target = const0_rtx;

  tree type = TREE_TYPE (exp);
  int unsignedp = TYPE_UNSIGNED (type);

  /* if (targetm.calls.promote_function_return(funtype))*/
  if (promote_function_mode(type, TYPE_MODE (type), &unsignedp,
                            fndecl ? TREE_TYPE (fndecl) : fntype, 0))
    {
      /* 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)))
        {
          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);
        }
    }

  /* If size of args is variable or this was a constructor call for a stack
     argument, restore saved stack-pointer value.  */

  if (old_stack_level)
    {
      emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
      stack_pointer_delta = old_stack_pointer_delta;
      pending_stack_adjust = old_pending_adj;
      old_stack_allocated = stack_pointer_delta - pending_stack_adjust;
      stack_arg_under_construction = old_stack_arg_under_construction;
      highest_outgoing_arg_in_use = initial_highest_arg_in_use;
      stack_usage_map = initial_stack_usage_map;
    }

  /* If this was alloca, record the new stack level for nonlocal gotos.
     Check for the handler slots since we might not have a save area
     for non-local gotos.  */

  if ((flags & ECF_MAY_BE_ALLOCA) && cfun->nonlocal_goto_save_area != 0)
    update_nonlocal_goto_save_area ();

  /* Free up storage we no longer need.  */
  for (i = 0; i < num_actuals; ++i)
    if (args[i].aligned_regs)
      free (args[i].aligned_regs);

  insns = get_insns ();
  end_sequence ();

  tail_call_insns = insns;

  /* Restore the pending stack adjustment now that we have
     finished generating the sibling call sequence.  */

  pending_stack_adjust = save_pending_stack_adjust;
  stack_pointer_delta = save_stack_pointer_delta;

  /* Prepare arg structure for next iteration.  */
  for (i = 0; i < num_actuals; i++)
    {
      args[i].value = 0;
      args[i].aligned_regs = 0;
      args[i].stack = 0;
    }

  sbitmap_free (stored_args_map);


  emit_insn(tail_call_insns);
  crtl->tail_call_emit = true;

  return target;
}


static void
preexpand_argument_expr (struct arg_data *arg,
                         int variable_size ATTRIBUTE_UNUSED)
{
  tree pval = arg->tree_value;
  rtx reg = 0;
  int partial = 0;

  if (TREE_CODE (pval) == ERROR_MARK)
    return;

  /* Push a new temporary level for any temporaries we make for
     this argument.  */
  push_temp_slots ();


  /* If this isn't going to be placed on both the stack and in registers,
     set up the register and number of words.  */
  if (! arg->pass_on_stack)
    {
      //if (flags & ECF_SIBCALL)
      reg = arg->tail_call_reg;
      //else
      //reg = arg->reg;
      partial = arg->partial;
    }

  /* Being passed entirely in a register.  We shouldn't be called in
     this case.  */
  gcc_assert (reg == 0 || partial != 0);

  /* If this arg needs special alignment, don't load the registers
     here.  */
  if (arg->n_aligned_regs != 0)
    reg = 0;

  /* Start a new sequence for the arg->exprs.  */
  start_sequence ();


  if (arg->pass_on_stack)
    stack_arg_under_construction++;

  arg->value = expand_expr (pval,
                            (partial
                             || TYPE_MODE (TREE_TYPE (pval)) != arg->mode)
                            ? NULL_RTX : arg->stack,
                            VOIDmode, EXPAND_STACK_PARM);

  /* If we are promoting object (or for any other reason) the mode
     doesn't agree, convert the mode.  */

  if (arg->mode != TYPE_MODE (TREE_TYPE (pval)))
    arg->value = convert_modes (arg->mode, TYPE_MODE (TREE_TYPE (pval)),
                                arg->value, arg->unsignedp);

  if (arg->pass_on_stack)
    stack_arg_under_construction--;

  arg->exprs = get_insns ();
  end_sequence ();

  if (arg->exprs) emit_insn(arg->exprs);

  preserve_temp_slots (arg->value);
  pop_temp_slots ();

  return ;
}

static int
expand_one_arg_push (struct arg_data *arg, rtx argblock, int flags,
                     int variable_size ATTRIBUTE_UNUSED, int reg_parm_stack_space)
{
  tree pval = arg->tree_value;
  int used = 0;
  int i, lower_bound = 0, upper_bound = 0;
  rtx reg = 0;
  int partial = 0;

  /* Push a new temporary level for any temporaries we make for
     this argument.  */
  push_temp_slots ();


  /* copy from store_one_arg.  modify here after.*/
  /* If this isn't going to be placed on both the stack and in registers,
     set up the register and number of words.  */
  if (! arg->pass_on_stack)
    {
      //if (flags & ECF_SIBCALL)
      reg = arg->tail_call_reg;
      //else
      //reg = arg->reg;
      partial = arg->partial;
    }
  /* Being passed entirely in a register.  We shouldn't be called in
     this case.  */
  gcc_assert (reg == 0 || partial != 0);
  /* If this arg needs special alignment, don't load the registers
     here.  */
  if (arg->n_aligned_regs != 0)
    reg = 0;




  if (arg->value == arg->stack)
    /* If the value is already in the stack slot, we are done.  */
    ;
  else if (arg->mode != BLKmode)
    {
      int size;

      /* Argument is a scalar, not entirely passed in registers.
         (If part is passed in registers, arg->partial says how much
         and emit_push_insn will take care of putting it there.)

         Push it, and if its size is less than the
         amount of space allocated to it,
         also bump stack pointer by the additional space.
         Note that in C the default argument promotions
         will prevent such mismatches.  */

      size = GET_MODE_SIZE (arg->mode);
      /* Compute how much space the push instruction will push.
         On many machines, pushing a byte will advance the stack
         pointer by a halfword.  */
#ifdef PUSH_ROUNDING
      size = PUSH_ROUNDING (size);
#endif
      used = size;

      /* Compute how much space the argument should get:
         round up to a multiple of the alignment for arguments.  */
      if (none != FUNCTION_ARG_PADDING (arg->mode, TREE_TYPE (pval)))
        used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1)
                 / (PARM_BOUNDARY / BITS_PER_UNIT))
                * (PARM_BOUNDARY / BITS_PER_UNIT));

      /* This isn't already where we want it on the stack, so put it there.
         This can either be done with push or copy insns.  */
      emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX,
                      PARM_BOUNDARY, partial, reg, used - size, argblock,
                      ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space,
                      ARGS_SIZE_RTX (arg->locate.alignment_pad));

      /* Unless this is a partially-in-register argument, the argument is now
         in the stack.  */
      if (partial == 0)
        arg->value = arg->stack;
    }
  else
    {
      /* BLKmode, at least partly to be pushed.  */

      unsigned int parm_align;
      int excess;
      rtx size_rtx;

      /* Pushing a nonscalar.
         If part is passed in registers, PARTIAL says how much
         and emit_push_insn will take care of putting it there.  */

      /* Round its size up to a multiple
         of the allocation unit for arguments.  */

      if (arg->locate.size.var != 0)
        {
          excess = 0;
          size_rtx = ARGS_SIZE_RTX (arg->locate.size);
        }
      else
        {
          /* PUSH_ROUNDING has no effect on us, because emit_push_insn
             for BLKmode is careful to avoid it.  */
          excess = (arg->locate.size.constant
                    - int_size_in_bytes (TREE_TYPE (pval))
                    + partial);
          size_rtx = expand_expr (size_in_bytes (TREE_TYPE (pval)),
                                  NULL_RTX, TYPE_MODE (sizetype), 0);
        }

      parm_align = arg->locate.boundary;

      /* When an argument is padded down, the block is aligned to
         PARM_BOUNDARY, but the actual argument isn't.  */
      if (FUNCTION_ARG_PADDING (arg->mode, TREE_TYPE (pval)) == downward)
        {
          if (arg->locate.size.var)
            parm_align = BITS_PER_UNIT;
          else if (excess)
            {
              unsigned int excess_align = (excess & -excess) * BITS_PER_UNIT;
              parm_align = MIN (parm_align, excess_align);
            }
        }

      if ((flags & ECF_SIBCALL) && MEM_P (arg->value))
        {
          /* emit_push_insn might not work properly if arg->value and
             argblock + arg->locate.offset areas overlap.  */
          rtx x = arg->value;
          int i = 0;

          if (XEXP (x, 0) == crtl->args.internal_arg_pointer
              || (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))
            {
              if (XEXP (x, 0) != crtl->args.internal_arg_pointer)
                i = INTVAL (XEXP (XEXP (x, 0), 1));

              /* expand_call should ensure this.  */
              gcc_assert (!arg->locate.offset.var
                          && GET_CODE (size_rtx) == CONST_INT);
            }
        }

      emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
                      parm_align, partial, reg, excess, argblock,
                      ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space,
                      ARGS_SIZE_RTX (arg->locate.alignment_pad));

      /* Unless this is a partially-in-register argument, the argument is now
         in the stack.

         ??? Unlike the case above, in which we want the actual
         address of the data, so that we can load it directly into a
         register, here we want the address of the stack slot, so that
         it's properly aligned for word-by-word copying or something
         like that.  It's not clear that this is always correct.  */
      if (partial == 0)
        arg->value = arg->stack_slot;
    }

  if (arg->reg && GET_CODE (arg->reg) == PARALLEL)
    {
      tree type = TREE_TYPE (arg->tree_value);
      arg->parallel_value
        = emit_group_load_into_temps (arg->reg, arg->value, type,
                                      int_size_in_bytes (type));
    }

  /* 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;

  /* Free any temporary slots made in processing this argument.  Show
     that we might have taken the address of something and pushed that
     as an operand.  */
  preserve_temp_slots (NULL_RTX);
  free_temp_slots ();
  pop_temp_slots ();

  return 0;
}

static void
determine_order(int *order, int num_actuals)
{
  int i;
  for (i=0; i<num_actuals; i++)
    order[i] = num_actuals-i-1;
  return;
}

static void
push_overlaps(struct arg_data *args, int num_actuals)
{
  int i;

  for (i=0; i<num_actuals; i++)
    {
      int dst_offset; /*  */
      int src_offset; /*  */
      rtx temp;
      if ( (dst_offset=check_frame_offset(args[i].stack)) < 0 ) continue;
      if ( (src_offset=check_frame_offset(args[i].value)) < 0 ) continue;

      /* 退避  */
      temp = assign_temp(args[i].tree_value, 1, 0, 0);
      if ( args[i].mode==BLKmode )
        emit_block_move ( temp, args[i].value, ARGS_SIZE_RTX(args[i].locate.size), 0 );
      else
        emit_move_insn ( temp, args[i].value );
      args[i].value = temp;

    }
  return;
}

static int
check_frame_offset(rtx x)
{
  int i;
  rtx addr;
  if ( !x || !MEM_P(x))
    return -1;

  addr = XEXP(x, 0);
  if (addr == crtl->args.internal_arg_pointer)
    i = 0;
  else if (GET_CODE (addr) == PLUS
           && XEXP (addr, 0) == crtl->args.internal_arg_pointer
           && GET_CODE (XEXP (addr, 1)) == CONST_INT)
    i = INTVAL (XEXP (addr, 1));
  else if (GET_CODE (addr) == PLUS
           && GET_CODE (XEXP (addr, 0)) == CONST_INT
           && XEXP (addr, 1) == crtl->args.internal_arg_pointer )
    i = INTVAL (XEXP (addr, 0));
  else
    return -1;

  return i;
}