OSDN Git Service

Allow passing nonaligned BLKmode structs in regs.
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 8 Feb 1993 10:51:58 +0000 (10:51 +0000)
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 8 Feb 1993 10:51:58 +0000 (10:51 +0000)
(struct arg_data): New fields aligned_regs and n_aligned_regs.
(expand_call): Set and use these fields when required.
(store_one_arg): Don't pass reg to emit_push_insn if we have previously
formed aligned registers.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@3440 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/calls.c

index 5b9c9ca..bd12293 100644 (file)
@@ -84,6 +84,14 @@ struct arg_data
   /* Place that this stack area has been saved, if needed.  */
   rtx save_area;
 #endif
+#ifdef STRICT_ALIGNMENT
+  /* If an argument's alignment does not permit direct copying into registers,
+     copy in smaller-sized pieces into pseudos.  These are stored in a
+     block pointed to by this field.  The next field says how many
+     word-sized pseudos we made.  */
+  rtx *aligned_regs;
+  int n_aligned_regs;
+#endif
 };
 
 #ifdef ACCUMULATE_OUTGOING_ARGS
@@ -514,7 +522,7 @@ expand_call (exp, target, ignore)
   rtx use_insns = 0;
 
   register tree p;
-  register int i;
+  register int i, j;
 
   /* See if we can find a DECL-node for the actual function.
      As a result, decide whether this is a call to an integrable function.  */
@@ -625,8 +633,6 @@ expand_call (exp, target, ignore)
       /* If inlining succeeded, return.  */
       if ((HOST_WIDE_INT) temp != -1)
        {
-         int i;
-
          /* Perform all cleanups needed for the arguments of this call
             (i.e. destructors in C++).  It is ok if these destructors
             clobber RETURN_VALUE_REG, because the only time we care about
@@ -1529,6 +1535,63 @@ expand_call (exp, target, ignore)
       store_one_arg (&args[i], argblock, may_be_alloca,
                     args_size.var != 0, fndecl, reg_parm_stack_space);
 
+#ifdef STRICT_ALIGNMENT
+  /* If we have a parm that is passed in registers but not in memory
+     and whose alignment does not permit a direct copy into registers,
+     make a group of pseudos that correspond to each register that we
+     will later fill.  */
+
+  for (i = 0; i < num_actuals; i++)
+    if (args[i].reg != 0 && ! args[i].pass_on_stack
+       && args[i].mode == BLKmode
+       && (TYPE_ALIGN (TREE_TYPE (args[i].tree_value))
+           < MIN (BIGGEST_ALIGNMENT, BITS_PER_WORD)))
+      {
+       int bytes = int_size_in_bytes (TREE_TYPE (args[i].tree_value));
+
+       args[i].n_aligned_regs
+         = args[i].partial ? args[i].partial
+           : (bytes + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
+
+       args[i].aligned_regs = (rtx *) alloca (sizeof (rtx)
+                                              * args[i].n_aligned_regs);
+
+       for (j = 0; j < args[i].n_aligned_regs; j++)
+         {
+           rtx reg = gen_reg_rtx (word_mode);
+           rtx word = operand_subword_force (args[i].value, j, BLKmode);
+           int bitsize = TYPE_ALIGN (TREE_TYPE (args[i].tree_value));
+           int bitpos;
+
+           args[i].aligned_regs[j] = reg;
+
+           /* Clobber REG and move each partword into it.  Ensure we don't
+              go past the end of the structure.  Note that the loop below
+              works because we've already verified that padding
+              and endianness are compatible.  */
+
+           emit_insn (gen_rtx (CLOBBER, VOIDmode, reg));
+
+           for (bitpos = 0;
+                bitpos < BITS_PER_WORD && bytes >= 0;
+                bitpos += bitsize, bytes -= bitsize / BITS_PER_UNIT)
+             {
+               int xbitpos = (BYTES_BIG_ENDIAN
+                              ? bitpos = BITS_PER_WORD - bitpos - bitsize
+                              : bitpos);
+
+               store_bit_field (reg, bitsize, xbitpos, word_mode,
+                                extract_bit_field (word, bitsize, xbitpos, 1,
+                                                   NULL_RTX, word_mode,
+                                                   word_mode,
+                                                   bitsize / BITS_PER_UNIT,
+                                                   BITS_PER_WORD),
+                                bitsize / BITS_PER_UNIT, BITS_PER_WORD);
+             }
+         }
+      }
+#endif
+
   /* Now store any partially-in-registers parm.
      This is the last place a block-move can happen.  */
   if (reg_parm_seen)
@@ -1609,6 +1672,17 @@ expand_call (exp, target, ignore)
 
          if (nregs == 0)
            emit_move_insn (reg, args[i].value);
+
+#ifdef STRICT_ALIGNMENT
+         /* If we have pre-computed the values to put in the registers in
+            the case of non-aligned structures, copy them in now.  */
+
+         else if (args[i].n_aligned_regs != 0)
+           for (j = 0; j < args[i].n_aligned_regs; j++)
+             emit_move_insn (gen_rtx (REG, word_mode, REGNO (reg) + j),
+                             args[i].aligned_regs[j]);
+#endif
+
          else if (args[i].partial == 0 || args[i].pass_on_stack)
            move_block_to_reg (REGNO (reg),
                               validize_mem (args[i].value), nregs,
@@ -1989,13 +2063,20 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
        this case.   */
     abort ();
 
+#ifdef STRICT_ALIGNMENT
+  /* If this arg needs special alignment, don't load the registers
+     here.  */
+  if (arg->n_aligned_regs != 0)
+    reg = 0;
+#endif
+  
   /* If this is being partially passed in a register, but multiple locations
      are specified, we assume that the one partially used is the one that is
      listed first.  */
   if (reg && GET_CODE (reg) == EXPR_LIST)
     reg = XEXP (reg, 0);
 
-  /* If this is being passes partially in a register, we can't evaluate
+  /* If this is being passed partially in a register, we can't evaluate
      it directly into its stack slot.  Otherwise, we can.  */
   if (arg->value == 0)
     {