mips.c (mips_va_arg): Fix calculation of osize for EABI_FLOAT_VARARGS_P.
authorRichard Sandiford <rsandifo@redhat.com>
Fri, 7 May 2004 15:09:23 +0000 (15:09 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Fri, 7 May 2004 15:09:23 +0000 (15:09 +0000)
* config/mips/mips.c (mips_va_arg): Fix calculation of osize for
EABI_FLOAT_VARARGS_P.

From-SVN: r81625

gcc/ChangeLog
gcc/config/mips/mips.c

index 6c3ba6ddaf27afd860141df889cf4262e184e02f..5b036b28e81dfa4ebf18e4ae8c75f39310057c2f 100644 (file)
@@ -1,3 +1,8 @@
+2004-05-07  Richard Sandiford  <rsandifo@redhat.com>
+
+       * config/mips/mips.c (mips_va_arg): Fix calculation of osize for
+       EABI_FLOAT_VARARGS_P.
+
 2004-05-07  Richard Sandiford  <rsandifo@redhat.com>
 
        * config/mips/mips.h (ISA_HAS_BRANCHLIKELY): Remove TARGET_MIPS5500.
index 09d826a94d72d775c41a9d68dc7f07fee380eb97..2925ffd3d96bcd0cc6afe2f9bb03d0228da7e287 100644 (file)
@@ -4133,8 +4133,6 @@ mips_va_arg (tree valist, tree type)
          rsize = UNITS_PER_WORD;
        }
 
-      addr_rtx = gen_reg_rtx (Pmode);
-
       if (!EABI_FLOAT_VARARGS_P)
        {
          /* Case of all args in a merged stack.  No need to check bounds,
@@ -4157,12 +4155,12 @@ mips_va_arg (tree valist, tree type)
 
          /* Emit code to set addr_rtx to the valist, and postincrement
             the valist by the size of the argument, rounded up to the
-            next word.  */
+            next word.  Account for padding on big-endian targets.  */
          t = build (POSTINCREMENT_EXPR, TREE_TYPE (gpr), gpr,
                     size_int (rsize));
-         r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
-         if (r != addr_rtx)
-           emit_move_insn (addr_rtx, r);
+         addr_rtx = expand_expr (t, 0, Pmode, EXPAND_NORMAL);
+         if (BYTES_BIG_ENDIAN)
+           addr_rtx = plus_constant (addr_rtx, rsize - size);
 
          /* Flush the POSTINCREMENT.  */
          emit_queue();
@@ -4176,6 +4174,8 @@ mips_va_arg (tree valist, tree type)
          rtx lab_over = NULL_RTX, lab_false;
          HOST_WIDE_INT osize;
 
+         addr_rtx = gen_reg_rtx (Pmode);
+
          f_ovfl = TYPE_FIELDS (va_list_type_node);
          f_gtop = TREE_CHAIN (f_ovfl);
          f_ftop = TREE_CHAIN (f_gtop);
@@ -4226,6 +4226,25 @@ mips_va_arg (tree valist, tree type)
                 each one will take up UNITS_PER_HWFPVALUE bytes, regardless
                 of the float's precision.  */
              rsize = UNITS_PER_HWFPVALUE;
+
+             /* Overflow arguments are padded to UNITS_PER_WORD bytes
+                (= PARM_BOUNDARY bits).  This can be different from RSIZE
+                in two cases:
+
+                    (1) On 32-bit targets when TYPE is a structure such as:
+
+                            struct s { float f; };
+
+                        Such structures are passed in paired FPRs, so RSIZE
+                        will be 8 bytes.  However, the structure only takes
+                        up 4 bytes of memory, so OSIZE will only be 4.
+
+                    (2) In combinations such as -mgp64 -msingle-float
+                        -fshort-double.  Doubles passed in registers
+                        will then take up 4 (UNITS_PER_HWFPVALUE) bytes,
+                        but those passed on the stack take up
+                        UNITS_PER_WORD bytes.  */
+             osize = MAX (GET_MODE_SIZE (TYPE_MODE (type)), UNITS_PER_WORD);
            }
          else
            {
@@ -4239,14 +4258,8 @@ mips_va_arg (tree valist, tree type)
                  t = build (MODIFY_EXPR, TREE_TYPE (off), off, t);
                  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
                }
+             osize = rsize;
            }
-         /* Every overflow argument must take up at least UNITS_PER_WORD
-            bytes (= PARM_BOUNDARY bits).  RSIZE can sometimes be smaller
-            than that, such as in the combination -mgp64 -msingle-float
-            -fshort-double.  Doubles passed in registers will then take
-            up UNITS_PER_HWFPVALUE bytes, but those passed on the stack
-            take up UNITS_PER_WORD bytes.  */
-         osize = MAX (rsize, UNITS_PER_WORD);
 
          /* [2] Emit code to branch if off == 0.  */
          r = expand_expr (off, NULL_RTX, TYPE_MODE (TREE_TYPE (off)),
@@ -4254,8 +4267,12 @@ mips_va_arg (tree valist, tree type)
          emit_cmp_and_jump_insns (r, const0_rtx, EQ, const1_rtx, GET_MODE (r),
                                   1, lab_false);
 
-         /* [4] Emit code for: addr_rtx = top - off.  */
+         /* [4] Emit code for: addr_rtx = top - off.  On big endian machines,
+            the argument has RSIZE - SIZE bytes of leading padding.  */
          t = build (MINUS_EXPR, TREE_TYPE (top), top, off);
+         if (BYTES_BIG_ENDIAN && rsize > size)
+           t = build (PLUS_EXPR, TREE_TYPE (t), t,
+                      build_int_2 (rsize - size, 0));
          r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
          if (r != addr_rtx)
            emit_move_insn (addr_rtx, r);
@@ -4285,12 +4302,12 @@ mips_va_arg (tree valist, tree type)
 
          /* [10, 11].  Emit code to store ovfl in addr_rtx, then
             post-increment ovfl by osize.  On big-endian machines,
-            the argument has OSIZE - RSIZE bytes of leading padding.  */
+            the argument has OSIZE - SIZE bytes of leading padding.  */
          t = build (POSTINCREMENT_EXPR, TREE_TYPE (ovfl), ovfl,
                     size_int (osize));
-         if (BYTES_BIG_ENDIAN && osize > rsize)
+         if (BYTES_BIG_ENDIAN && osize > size)
            t = build (PLUS_EXPR, TREE_TYPE (t), t,
-                      build_int_2 (osize - rsize, 0));
+                      build_int_2 (osize - size, 0));
          r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
          if (r != addr_rtx)
            emit_move_insn (addr_rtx, r);
@@ -4298,8 +4315,6 @@ mips_va_arg (tree valist, tree type)
          emit_queue();
          emit_label (lab_over);
        }
-      if (BYTES_BIG_ENDIAN && rsize != size)
-       addr_rtx = plus_constant (addr_rtx, rsize - size);
       if (indirect)
        {
          addr_rtx = force_reg (Pmode, addr_rtx);