]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
expr.c (emit_group_load): Revise to allow splitting TCmode source into DImode pieces.
authorJohn David Anglin <dave@hiauly1.hia.nrc.ca>
Wed, 4 Sep 2002 18:09:32 +0000 (18:09 +0000)
committerJohn David Anglin <danglin@gcc.gnu.org>
Wed, 4 Sep 2002 18:09:32 +0000 (18:09 +0000)
* expr.c (emit_group_load): Revise to allow splitting TCmode source
into DImode pieces.
* pa-64.h (LONG_DOUBLE_TYPE_SIZE): Define to 128.
* pa64-regs.h (CLASS_CANNOT_CHANGE_MODE_P): Inhibit changes from SImode
for floating-point register class.
* pa.c (function_arg): Fix handling of modes wider than one word for
TARGET_64BIT.

From-SVN: r56805

gcc/ChangeLog
gcc/config/pa/pa-64.h
gcc/config/pa/pa.c
gcc/config/pa/pa64-regs.h
gcc/expr.c

index 682001bb49175397baebc6f5fffaa11c05a1d3a0..e7d7646dc4947ce6a4b448a470cae44262d0690f 100644 (file)
@@ -1,3 +1,14 @@
+2002-09-04  John David Anglin  <dave@hiauly1.hia.nrc.ca>
+
+       * expr.c (emit_group_load): Revise to allow splitting TCmode source
+       into DImode pieces.
+
+       * pa-64.h (LONG_DOUBLE_TYPE_SIZE): Define to 128.
+       * pa64-regs.h (CLASS_CANNOT_CHANGE_MODE_P): Inhibit changes from SImode
+       for floating-point register class.
+       * pa.c (function_arg): Fix handling of modes wider than one word for
+       TARGET_64BIT.
+
 Wed Sep  4 18:48:10 2002  J"orn Rennecke <joern.rennecke@superh.com>
 
        * combine.c (make_compound_operation): Don't generate zero / sign
index 2658038c51f6c9cf656e1c0c4f422d14d7011544..82ce3ef45f276f60c4e84da45be2a0317863a97a 100644 (file)
@@ -65,10 +65,8 @@ Boston, MA 02111-1307, USA.  */
 #define FLOAT_TYPE_SIZE 32
 #undef DOUBLE_TYPE_SIZE
 #define DOUBLE_TYPE_SIZE 64
-/* This should be 128, but until we work out the ABI for the 128bit
-   FP codes supplied by HP we'll keep it at 64 bits.  */
 #undef LONG_DOUBLE_TYPE_SIZE
-#define LONG_DOUBLE_TYPE_SIZE 64
+#define LONG_DOUBLE_TYPE_SIZE 128
 
 /* Temporary until we figure out what to do with those *(&@$ 32bit
    relocs which appear in stabs.  */
index 718ad1382a10e2b19fdb9658c2e7b97d0d1ef5fc..2d655394a0daac0a5fc9719cc984a0f8c6056ab6 100644 (file)
@@ -7446,6 +7446,8 @@ function_arg (cum, mode, type, named, incoming)
      int incoming;
 {
   int max_arg_words = (TARGET_64BIT ? 8 : 4);
+  int arg_size = FUNCTION_ARG_SIZE (mode, type);
+  int alignment = 0;
   int fpr_reg_base;
   int gpr_reg_base;
   rtx retval;
@@ -7456,16 +7458,15 @@ function_arg (cum, mode, type, named, incoming)
          this routine should return zero.  FUNCTION_ARG_PARTIAL_NREGS will
          handle arguments which are split between regs and stack slots if
          the ABI mandates split arguments.  */
-      if (cum->words + FUNCTION_ARG_SIZE (mode, type) > max_arg_words
+      if (cum->words + arg_size > max_arg_words
           || mode == VOIDmode)
        return NULL_RTX;
     }
   else
     {
-      int offset = 0;
-      if (FUNCTION_ARG_SIZE (mode, type) > 1 && (cum->words & 1))
-       offset = 1;
-      if (cum->words + offset >= max_arg_words
+      if (arg_size > 1)
+       alignment = cum->words & 1;
+      if (cum->words + alignment >= max_arg_words
          || mode == VOIDmode)
        return NULL_RTX;
     }
@@ -7474,70 +7475,54 @@ function_arg (cum, mode, type, named, incoming)
      particularly in their handling of FP registers.  We might
      be able to cleverly share code between them, but I'm not
      going to bother in the hope that splitting them up results
-     in code that is more easily understood.
+     in code that is more easily understood.  */
 
-     The 64bit code probably is very wrong for structure passing.  */
   if (TARGET_64BIT)
     {
       /* Advance the base registers to their current locations.
 
          Remember, gprs grow towards smaller register numbers while
-        fprs grow to higher register numbers.  Also remember FP regs
-        are always 4 bytes wide, while the size of an integer register
-        varies based on the size of the target word.  */
+        fprs grow to higher register numbers.  Also remember that
+        although FP regs are 32-bit addressable, we pretend that
+        the registers are 64-bits wide.  */
       gpr_reg_base = 26 - cum->words;
       fpr_reg_base = 32 + cum->words;
 
-      /* If the argument is more than a word long, then we need to align
-        the base registers.  Same caveats as above.  */
-      if (FUNCTION_ARG_SIZE (mode, type) > 1)
+      /* Arguments wider than one word need special treatment.  */
+      if (arg_size > 1)
        {
-         if (mode != BLKmode)
+         /* Double-extended precision (80-bit), quad-precision (128-bit)
+            and aggregates including complex numbers are aligned on
+            128-bit boundaries.  The first eight 64-bit argument slots
+            are associated one-to-one, with general registers r26
+            through r19, and also with floating-point registers fr4
+            through fr11.  Arguments larger than one word are always
+            passed in general registers.  */
+
+         rtx loc[8];
+         int i, offset = 0, ub = arg_size;
+
+         /* Align the base register.  */
+         gpr_reg_base -= alignment;
+
+         ub = MIN (ub, max_arg_words - cum->words - alignment);
+         for (i = 0; i < ub; i++)
            {
-             /* First deal with alignment of the doubleword.  */
-             gpr_reg_base -= (cum->words & 1);
-
-             /* This seems backwards, but it is what HP specifies.  We need
-                gpr_reg_base to point to the smaller numbered register of
-                the integer register pair.  So if we have an even register
-                 number, then decrement the gpr base.  */
-             gpr_reg_base -= ((gpr_reg_base % 2) == 0);
-
-             /* FP values behave sanely, except that each FP reg is only
-                half of word.  */
-             fpr_reg_base += ((fpr_reg_base % 2) == 0);
-            }
-         else
-           {
-             rtx loc[8];
-             int i, offset = 0, ub;
-              ub = FUNCTION_ARG_SIZE (mode, type);
-             ub = MIN (ub,
-                       MAX (0, max_arg_words - cum->words - (cum->words & 1)));
-             gpr_reg_base -= (cum->words & 1);
-             for (i = 0; i < ub; i++)
-               {
-                 loc[i] = gen_rtx_EXPR_LIST (VOIDmode,
-                                             gen_rtx_REG (DImode,
-                                                          gpr_reg_base),
-                                             GEN_INT (offset));
-                 gpr_reg_base -= 1;
-                 offset += 8;
-               }
-             if (ub == 0)
-               return NULL_RTX;
-             else if (ub == 1)
-               return XEXP (loc[0], 0);
-             else
-               return gen_rtx_PARALLEL (mode, gen_rtvec_v (ub, loc));
+             loc[i] = gen_rtx_EXPR_LIST (VOIDmode,
+                                         gen_rtx_REG (DImode, gpr_reg_base),
+                                         GEN_INT (offset));
+             gpr_reg_base -= 1;
+             offset += 8;
            }
+
+         return gen_rtx_PARALLEL (mode, gen_rtvec_v (ub, loc));
        }
     }
   else
     {
       /* If the argument is larger than a word, then we know precisely
         which registers we must use.  */
-      if (FUNCTION_ARG_SIZE (mode, type) > 1)
+      if (arg_size > 1)
        {
          if (cum->words)
            {
@@ -7559,19 +7544,6 @@ function_arg (cum, mode, type, named, incoming)
        }
     }
 
-  if (TARGET_64BIT && mode == TFmode)
-    {
-      return
-       gen_rtx_PARALLEL
-         (mode,
-          gen_rtvec (2,
-                     gen_rtx_EXPR_LIST (VOIDmode,
-                                        gen_rtx_REG (DImode, gpr_reg_base + 1),
-                                        const0_rtx),
-                     gen_rtx_EXPR_LIST (VOIDmode,
-                                        gen_rtx_REG (DImode, gpr_reg_base),
-                                        GEN_INT (8))));
-    }
   /* Determine if the argument needs to be passed in both general and
      floating point registers.  */
   if (((TARGET_PORTABLE_RUNTIME || TARGET_64BIT || TARGET_ELF32)
index b193c99b075ed1a75035049d485f686ee55da835..0af4c5fb2706cd9d104f4c330dfaf7a7293e3d93 100644 (file)
@@ -234,16 +234,21 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FPUPPER_REGS, FP_REGS,
 
 /* If defined, gives a class of registers that cannot be used as the
    operand of a SUBREG that changes the mode of the object illegally.  */
-/* ??? This may not actually be necessary anymore.  But until I can prove
-   otherwise it will stay.  */
+
 #define CLASS_CANNOT_CHANGE_MODE       (FP_REGS)
 
-/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE.  */
-#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \
-  (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
+/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE.
+
+   SImode loads to floating-point registers are not zero-extended.
+   The definition for LOAD_EXTEND_OP specifies that integer loads
+   narrower than BITS_PER_WORD will be zero-extended.  As a result,
+   we inhibit changes from SImode unless they are to a mode that is
+   identical in size.  */
+
+#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO)                            \
+  ((FROM) == SImode && GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO))
 
-/* The same information, inverted:
-   Return the class number of the smallest class containing
+/* Return the class number of the smallest class containing
    reg number REGNO.  This could be a conditional expression
    or could index an array.  */
 
index ca8952bffc703c8d25cef659b2a6e89b51b20561..5872ab055fb948a42d8c1bd69d66c566f67fadad 100644 (file)
@@ -2265,21 +2265,26 @@ emit_group_load (dst, orig_src, ssize)
        }
       else if (GET_CODE (src) == CONCAT)
        {
-         if ((bytepos == 0
-              && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 0))))
-             || (bytepos == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
-                 && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 1)))))
+         unsigned int slen = GET_MODE_SIZE (GET_MODE (src));
+         unsigned int slen0 = GET_MODE_SIZE (GET_MODE (XEXP (src, 0)));
+
+         if ((bytepos == 0 && bytelen == slen0)
+             || (bytepos != 0 && bytepos + bytelen <= slen))
            {
-             tmps[i] = XEXP (src, bytepos != 0);
+             /* The following assumes that the concatenated objects all
+                have the same size.  In this case, a simple calculation
+                can be used to determine the object and the bit field
+                to be extracted.  */
+             tmps[i] = XEXP (src, bytepos / slen0);
              if (! CONSTANT_P (tmps[i])
                  && (GET_CODE (tmps[i]) != REG || GET_MODE (tmps[i]) != mode))
                tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT,
-                                            0, 1, NULL_RTX, mode, mode, ssize);
+                                            (bytepos % slen0) * BITS_PER_UNIT,
+                                            1, NULL_RTX, mode, mode, ssize);
            }
          else if (bytepos == 0)
            {
-             rtx mem = assign_stack_temp (GET_MODE (src),
-                                          GET_MODE_SIZE (GET_MODE (src)), 0);
+             rtx mem = assign_stack_temp (GET_MODE (src), slen, 0);
              emit_move_insn (mem, src);
              tmps[i] = adjust_address (mem, mode, 0);
            }