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]

Re: [PATCH] - Use of powerpc 64bit instructions in 32bit ABI


>>>>> Ulrich Weigand writes:

Ulrich> Could you elaborate what the problem with struct-by-value was?
Ulrich> This appears to work fine for me by returning false from
Ulrich> FUNCTION_ARG_PASS_BY_REFERENCE and then returning a PARALLEL
Ulrich> from FUNCTION_ARG for that struct parameter.

	Notice the use of UNITS_PER_WORD, BITS_PER_WORD, and word_mode in
the following functions that depend on the argument wordsize and ABI:

calls.c:load_register_parameters()

          else if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode)
            {
              size = int_size_in_bytes (TREE_TYPE (args[i].tree_value));
              nregs = (size + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD; <***
            }


calls.c:store_one_arg()

      /* 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 * UNITS_PER_WORD); <***
          size_rtx = expand_expr (size_in_bytes (TREE_TYPE (pval)),
                                  NULL_RTX, TYPE_MODE (sizetype), 0);
        }


expr.c:emit_push_insn()

  if (mode == BLKmode)
    {
      /* Copy a block into the stack, entirely or partially.  */

      rtx temp;
      int used = partial * UNITS_PER_WORD; <***

...

  else if (partial > 0)
    {
      /* Scalar partly in registers.  */

      int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD; <***
      int i;
      int not_stack;
      /* # words of start of argument
         that we must make space for but need not store.  */
      int offset = partial % (PARM_BOUNDARY / BITS_PER_WORD); <***
...
        if (i >= not_stack + offset)
          emit_push_insn (operand_subword_force (x, i, mode),
                     ***> word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX,
                          0, args_addr,
                          GEN_INT (args_offset + ((i - not_stack + skip)
                                                  * UNITS_PER_WORD)),
                          reg_parm_stack_space, alignment_pad);


function.c:assign_parm()

      if (nominal_mode == BLKmode
#ifdef BLOCK_REG_PADDING
          || (locate.where_pad == (BYTES_BIG_ENDIAN ? upward : downward)
              && GET_MODE_SIZE (promoted_mode) < UNITS_PER_WORD) <***
#endif
          || GET_CODE (entry_parm) == PARALLEL)
        {
          /* If a BLKmode arrives in registers, copy it to a stack slot.
             Handle calls that pass values in multiple non-contiguous
             locations.  The Irix 6 ABI has examples of this.  */
          if (GET_CODE (entry_parm) == REG
              || GET_CODE (entry_parm) == PARALLEL)
            {
              int size = int_size_in_bytes (TREE_TYPE (parm));
              int size_stored = CEIL_ROUND (size, UNITS_PER_WORD); <***
...
              /* If SIZE is that of a mode no bigger than a word, just use
                 that mode's store operation.  */
              else if (size <= UNITS_PER_WORD) <***
                {
                  enum machine_mode mode
                    = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);

                  if (mode != BLKmode
#ifdef BLOCK_REG_PADDING
                      && (size == UNITS_PER_WORD <***
                          || (BLOCK_REG_PADDING (mode, TREE_TYPE (parm), 1)
                              != (BYTES_BIG_ENDIAN ? upward : downward)))
#endif
                      )
                    {
                      rtx reg = gen_rtx_REG (mode, REGNO (entry_parm));
                      emit_move_insn (change_address (mem, mode, 0), reg);
                    }

                  /* Blocks smaller than a word on a BYTES_BIG_ENDIAN
                     machine must be aligned to the left before storing
                     to memory.  Note that the previous test doesn't
                     handle all cases (e.g. SIZE == 3).  */
                  else if (size != UNITS_PER_WORD <***
#ifdef BLOCK_REG_PADDING
                           && (BLOCK_REG_PADDING (mode, TREE_TYPE (parm), 1)
                               == downward)
#else
                           && BYTES_BIG_ENDIAN
#endif
                           )
                    {
                      rtx tem, x;
                      int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT; <***
                      rtx reg = gen_rtx_REG (word_mode, REGNO (entry_parm));

                      x = expand_binop (word_mode, ashl_optab, reg,
                                        GEN_INT (by), 0, 1, OPTAB_WIDEN);
                      tem = change_address (mem, word_mode, 0);
                      emit_move_insn (tem, x);
                    }
                  else
                    move_block_from_reg (REGNO (entry_parm), mem,
                                         size_stored / UNITS_PER_WORD); <***
                }
              else
                move_block_from_reg (REGNO (entry_parm), mem,
                                     size_stored / UNITS_PER_WORD); <***
            }
          SET_DECL_RTL (parm, stack_parm);
        }


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