OSDN Git Service

* expr.c (emit_group_load, emit_group_store): Rewrite considering
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 1 Jul 1998 05:10:51 +0000 (05:10 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 1 Jul 1998 05:10:51 +0000 (05:10 +0000)
        the size and alignment of the structure being manipulated.
        * expr.c, calls.c, function.c: Update all callers.
        * expr.h: Update prototypes.
        * cse.c (invalidate): Cope with parallels.

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

gcc/ChangeLog
gcc/calls.c
gcc/cse.c
gcc/expr.c
gcc/expr.h
gcc/function.c

index f468786..ff467bf 100644 (file)
@@ -1,3 +1,11 @@
+Wed Jul  1 05:04:41 1998  Richard Henderson  <rth@cygnus.com>
+
+       * expr.c (emit_group_load, emit_group_store): Rewrite considering
+       the size and alignment of the structure being manipulated. 
+       * expr.c, calls.c, function.c: Update all callers.
+       * expr.h: Update prototypes.
+       * cse.c (invalidate): Cope with parallels.
+
 Wed Jul  1 04:22:23 1998  Richard Henderson  <rth@cygnus.com>
 
        * sparc.c (function_arg_record_value): Take a MODE arg with which to
index 6271a61..8b14019 100644 (file)
@@ -1922,7 +1922,12 @@ expand_call (exp, target, ignore)
             locations.  The Irix 6 ABI has examples of this.  */
 
          if (GET_CODE (reg) == PARALLEL)
-           emit_group_load (reg, args[i].value);
+           {
+             emit_group_load (reg, args[i].value,
+                              int_size_in_bytes (TREE_TYPE (args[i].tree_value)),
+                              (TYPE_ALIGN (TREE_TYPE (args[i].tree_value))
+                               / BITS_PER_UNIT));
+           }
 
          /* If simple case, just do move.  If normal partial, store_one_arg
             has already loaded the register for us.  In all other cases,
@@ -2089,15 +2094,17 @@ expand_call (exp, target, ignore)
      The Irix 6 ABI has examples of this.  */
   else if (GET_CODE (valreg) == PARALLEL)
     {
+      int bytes = int_size_in_bytes (TREE_TYPE (exp));
+
       if (target == 0)
        {
-         int bytes = int_size_in_bytes (TREE_TYPE (exp));
          target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)), bytes, 0);
          MEM_IN_STRUCT_P (target) = AGGREGATE_TYPE_P (TREE_TYPE (exp));
          preserve_temp_slots (target);
        }
 
-      emit_group_store (target, valreg);
+      emit_group_store (target, valreg, bytes,
+                       TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
     }
   else if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp))
           && GET_MODE (target) == GET_MODE (valreg))
index bd2aa56..3705511 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1609,6 +1609,24 @@ invalidate (x, full_mode)
       return;
     }
 
+  /* If X is a parallel, invalidate all of its elements.  */
+
+  if (GET_CODE (x) == PARALLEL)
+    {
+      for (i = XVECLEN (x, 0) - 1; i >= 0 ; --i)
+       invalidate (XVECEXP (x, 0, i), VOIDmode);
+      return;
+    }
+
+  /* If X is an expr_list, this is part of a disjoint return value;
+     extract the location in question ignoring the offset.  */
+
+  if (GET_CODE (x) == EXPR_LIST)
+    {
+      invalidate (XEXP (x, 0), VOIDmode);
+      return;
+    }
+
   /* X is not a register; it must be a memory reference with
      a nonvarying address.  Remove all hash table elements
      that refer to overlapping pieces of memory.  */
index e01f08a..a7abc5a 100644 (file)
@@ -1822,103 +1822,187 @@ move_block_from_reg (regno, x, nregs, size)
     }
 }
 
-/* Emit code to move a block Y to a block X, where X is non-consecutive
-   registers represented by a PARALLEL.  */
+/* Emit code to move a block SRC to a block DST, where DST is non-consecutive
+   registers represented by a PARALLEL.  SSIZE represents the total size of
+   block SRC in bytes, or -1 if not known.  ALIGN is the known alignment of
+   SRC in bits.  */
+/* ??? If SSIZE % UNITS_PER_WORD != 0, we make the blatent assumption that
+   the balance will be in what would be the low-order memory addresses, i.e.
+   left justified for big endian, right justified for little endian.  This
+   happens to be true for the targets currently using this support.  If this
+   ever changes, a new target macro along the lines of FUNCTION_ARG_PADDING
+   would be needed.  */
 
 void
-emit_group_load (x, y)
-     rtx x, y;
+emit_group_load (dst, orig_src, ssize, align)
+     rtx dst, orig_src;
+     int align, ssize;
 {
-  rtx target_reg, source;
-  int i;
+  rtx *tmps, src;
+  int start, i;
 
-  if (GET_CODE (x) != PARALLEL)
+  if (GET_CODE (dst) != PARALLEL)
     abort ();
 
   /* Check for a NULL entry, used to indicate that the parameter goes
      both on the stack and in registers.  */
-  if (XEXP (XVECEXP (x, 0, 0), 0))
-    i = 0;
+  if (XEXP (XVECEXP (dst, 0, 0), 0))
+    start = 0;
   else
-    i = 1;
-
-  for (; i < XVECLEN (x, 0); i++)
-    {
-      rtx element = XVECEXP (x, 0, i);
-
-      target_reg = XEXP (element, 0);
-
-      if (GET_CODE (y) == MEM)
-       source = change_address (y, GET_MODE (target_reg),
-                                plus_constant (XEXP (y, 0),
-                                               INTVAL (XEXP (element, 1))));
-      else if (XEXP (element, 1) == const0_rtx)
-       {
-         if (GET_MODE (target_reg) == GET_MODE (y))
-           source = y;
-         /* Allow for the target_reg to be smaller than the input register
-            to allow for AIX with 4 DF arguments after a single SI arg.  The
-            last DF argument will only load 1 word into the integer registers,
-            but load a DF value into the float registers.  */
-         else if ((GET_MODE_SIZE (GET_MODE (target_reg))
-                   <= GET_MODE_SIZE (GET_MODE (y)))
-                  && GET_MODE (target_reg) == word_mode)
-           /* This might be a const_double, so we can't just use SUBREG.  */
-           source = operand_subword (y, 0, 0, VOIDmode);
-         else if (GET_MODE_SIZE (GET_MODE (target_reg))
-                  == GET_MODE_SIZE (GET_MODE (y)))
-           source = gen_lowpart (GET_MODE (target_reg), y);
-         else
-           abort ();       
+    start = 1;
+
+  tmps = (rtx *) alloca (sizeof(rtx) * XVECLEN (dst, 0));
+
+  /* If we won't be loading directly from memory, protect the real source
+     from strange tricks we might play.  */
+  src = orig_src;
+  if (GET_CODE (src) != MEM)
+    {
+      src = gen_reg_rtx (GET_MODE (orig_src));
+      emit_move_insn (src, orig_src);
+    }
+
+  /* Process the pieces.  */
+  for (i = start; i < XVECLEN (dst, 0); i++)
+    {
+      enum machine_mode mode = GET_MODE (XEXP (XVECEXP (dst, 0, i), 0));
+      int bytepos = INTVAL (XEXP (XVECEXP (dst, 0, i), 1));
+      int bytelen = GET_MODE_SIZE (mode);
+      int shift = 0;
+
+      /* Handle trailing fragments that run over the size of the struct.  */
+      if (ssize >= 0 && bytepos + bytelen > ssize)
+       {
+         shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
+         bytelen = ssize - bytepos;
+         if (bytelen <= 0)
+           abort();
+       }
+
+      /* Optimize the access just a bit.  */
+      if (GET_CODE (src) == MEM
+         && align*BITS_PER_UNIT >= GET_MODE_ALIGNMENT (mode)
+         && bytepos*BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
+         && bytelen == GET_MODE_SIZE (mode))
+       {
+         tmps[i] = gen_reg_rtx (mode);
+         emit_move_insn (tmps[i],
+                         change_address (src, mode,
+                                         plus_constant (XEXP (src, 0),
+                                                        bytepos)));
        }
       else
-       abort ();
+       {
+         tmps[i] = extract_bit_field (src, bytelen*BITS_PER_UNIT,
+                                      bytepos*BITS_PER_UNIT, 1, NULL_RTX,
+                                      mode, mode, align, ssize);
+       }
 
-      emit_move_insn (target_reg, source);
+      if (BYTES_BIG_ENDIAN && shift)
+       {
+         expand_binop (mode, ashl_optab, tmps[i], GEN_INT (shift),
+                       tmps[i], 0, OPTAB_WIDEN);
+       }
     }
+  emit_queue();
+
+  /* Copy the extracted pieces into the proper (probable) hard regs.  */
+  for (i = start; i < XVECLEN (dst, 0); i++)
+    emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
 }
 
-/* Emit code to move a block Y to a block X, where Y is non-consecutive
-   registers represented by a PARALLEL.  */
+/* Emit code to move a block SRC to a block DST, where SRC is non-consecutive
+   registers represented by a PARALLEL.  SSIZE represents the total size of
+   block DST, or -1 if not known.  ALIGN is the known alignment of DST.  */
 
 void
-emit_group_store (x, y)
-     rtx x, y;
+emit_group_store (orig_dst, src, ssize, align)
+     rtx orig_dst, src;
+     int ssize, align;
 {
-  rtx source_reg, target;
-  int i;
+  rtx *tmps, dst;
+  int start, i;
 
-  if (GET_CODE (y) != PARALLEL)
+  if (GET_CODE (src) != PARALLEL)
     abort ();
 
   /* Check for a NULL entry, used to indicate that the parameter goes
      both on the stack and in registers.  */
-  if (XEXP (XVECEXP (y, 0, 0), 0))
-    i = 0;
+  if (XEXP (XVECEXP (src, 0, 0), 0))
+    start = 0;
   else
-    i = 1;
+    start = 1;
 
-  for (; i < XVECLEN (y, 0); i++)
+  tmps = (rtx *) alloca (sizeof(rtx) * XVECLEN (src, 0));
+
+  /* Copy the (probable) hard regs into pseudos.  */
+  for (i = start; i < XVECLEN (src, 0); i++)
     {
-      rtx element = XVECEXP (y, 0, i);
+      rtx reg = XEXP (XVECEXP (src, 0, i), 0);
+      tmps[i] = gen_reg_rtx (GET_MODE (reg));
+      emit_move_insn (tmps[i], reg);
+    }
+  emit_queue();
 
-      source_reg = XEXP (element, 0);
+  /* If we won't be storing directly into memory, protect the real destination
+     from strange tricks we might play.  */
+  dst = orig_dst;
+  if (GET_CODE (dst) != MEM)
+    {
+      dst = gen_reg_rtx (GET_MODE (orig_dst));
+      /* Make life a bit easier for combine.  */
+      emit_move_insn (dst, const0_rtx);
+    }
+  else if (! MEM_IN_STRUCT_P (dst))
+    {
+      /* store_bit_field requires that memory operations have
+        mem_in_struct_p set; we might not.  */
 
-      if (GET_CODE (x) == MEM)
-       target = change_address (x, GET_MODE (source_reg),
-                                plus_constant (XEXP (x, 0),
-                                               INTVAL (XEXP (element, 1))));
-      else if (XEXP (element, 1) == const0_rtx)
+      dst = copy_rtx (orig_dst);
+      MEM_IN_STRUCT_P (dst) = 1;
+    }
+
+  /* Process the pieces.  */
+  for (i = start; i < XVECLEN (src, 0); i++)
+    {
+      int bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
+      enum machine_mode mode = GET_MODE (tmps[i]);
+      int bytelen = GET_MODE_SIZE (mode);
+
+      /* Handle trailing fragments that run over the size of the struct.  */
+      if (ssize >= 0 && bytepos + bytelen > ssize)
        {
-         target = x;
-         if (GET_MODE (target) != GET_MODE (source_reg))
-           target = gen_lowpart (GET_MODE (source_reg), target);
+         if (BYTES_BIG_ENDIAN)
+           {
+             int shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
+             expand_binop (mode, ashr_optab, tmps[i], GEN_INT (shift),
+                           tmps[i], 0, OPTAB_WIDEN);
+           }
+         bytelen = ssize - bytepos;
        }
-      else
-       abort ();
 
-      emit_move_insn (target, source_reg);
+      /* Optimize the access just a bit.  */
+      if (GET_CODE (dst) == MEM
+         && align*BITS_PER_UNIT >= GET_MODE_ALIGNMENT (mode)
+         && bytepos*BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
+         && bytelen == GET_MODE_SIZE (mode))
+       {
+         emit_move_insn (change_address (dst, mode,
+                                         plus_constant (XEXP (dst, 0),
+                                                        bytepos)),
+                         tmps[i]);
+       }
+      else
+       {
+         store_bit_field (dst, bytelen*BITS_PER_UNIT, bytepos*BITS_PER_UNIT,
+                          mode, tmps[i], align, ssize);
+       }
     }
+  emit_queue();
+
+  /* Copy from the pseudo into the (probable) hard reg.  */
+  if (GET_CODE (dst) == REG)
+    emit_move_insn (orig_dst, dst);
 }
 
 /* Add a USE expression for REG to the (possibly empty) list pointed
@@ -2862,7 +2946,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
       /* Handle calls that pass values in multiple non-contiguous locations.
         The Irix 6 ABI has examples of this.  */
       if (GET_CODE (reg) == PARALLEL)
-       emit_group_load (reg, x);
+       emit_group_load (reg, x, -1, align);  /* ??? size? */
       else
        move_block_to_reg (REGNO (reg), x, partial, mode);
     }
@@ -3071,7 +3155,8 @@ expand_assignment (to, from, want_value, suggest_reg)
       /* Handle calls that return values in multiple non-contiguous locations.
         The Irix 6 ABI has examples of this.  */
       if (GET_CODE (to_rtx) == PARALLEL)
-       emit_group_load (to_rtx, value);
+       emit_group_load (to_rtx, value, int_size_in_bytes (TREE_TYPE (from)),
+                        TYPE_ALIGN (TREE_TYPE (from)) / BITS_PER_UNIT);
       else if (GET_MODE (to_rtx) == BLKmode)
        emit_block_move (to_rtx, value, expr_size (from),
                         TYPE_ALIGN (TREE_TYPE (from)) / BITS_PER_UNIT);
@@ -3476,7 +3561,8 @@ store_expr (exp, target, want_value)
       /* Handle calls that return values in multiple non-contiguous locations.
         The Irix 6 ABI has examples of this.  */
       else if (GET_CODE (target) == PARALLEL)
-       emit_group_load (target, temp);
+       emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)),
+                        TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
       else if (GET_MODE (temp) == BLKmode)
        emit_block_move (target, temp, expr_size (exp),
                         TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
index f75828f..11f4673 100644 (file)
@@ -714,10 +714,10 @@ extern void move_block_from_reg PROTO((int, rtx, int, int));
 
 /* Load a BLKmode value into non-consecutive registers represented by a
    PARALLEL.  */
-extern void emit_group_load PROTO((rtx, rtx));
+extern void emit_group_load PROTO((rtx, rtx, int, int));
 /* Store a BLKmode value from non-consecutive registers represented by a
    PARALLEL.  */
-extern void emit_group_store PROTO((rtx, rtx));
+extern void emit_group_store PROTO((rtx, rtx, int, int));
 
 /* Mark REG as holding a parameter for the next CALL_INSN.  */
 extern void use_reg PROTO((rtx *, rtx));
index 9150ebc..67bbc69 100644 (file)
@@ -3945,8 +3945,10 @@ assign_parms (fndecl, second_time)
                  /* Handle calls that pass values in multiple non-contiguous
                     locations.  The Irix 6 ABI has examples of this.  */
                  if (GET_CODE (entry_parm) == PARALLEL)
-                   emit_group_store (validize_mem (stack_parm),
-                                        entry_parm);
+                   emit_group_store (validize_mem (stack_parm), entry_parm,
+                                     int_size_in_bytes (TREE_TYPE (parm)),
+                                     (TYPE_ALIGN (TREE_TYPE (parm))
+                                      / BITS_PER_UNIT));
                  else
                    move_block_from_reg (REGNO (entry_parm),
                                         validize_mem (stack_parm), nregs,
@@ -4116,7 +4118,10 @@ assign_parms (fndecl, second_time)
              /* Handle calls that pass values in multiple non-contiguous
                 locations.  The Irix 6 ABI has examples of this.  */
              if (GET_CODE (entry_parm) == PARALLEL)
-               emit_group_store (validize_mem (stack_parm), entry_parm);
+               emit_group_store (validize_mem (stack_parm), entry_parm,
+                                 int_size_in_bytes (TREE_TYPE (parm)),
+                                 (TYPE_ALIGN (TREE_TYPE (parm))
+                                  / BITS_PER_UNIT));
              else
                move_block_from_reg (REGNO (entry_parm),
                                     validize_mem (stack_parm),