calls.c (expand_call): Encapsulate code into copy_blkmode_from_reg.
authorGavin Romig-Koch <gavin@cygnus.com>
Thu, 1 Oct 1998 13:00:21 +0000 (13:00 +0000)
committerGavin Romig-Koch <gavin@gcc.gnu.org>
Thu, 1 Oct 1998 13:00:21 +0000 (13:00 +0000)
* calls.c (expand_call) : Encapsulate code into
copy_blkmode_from_reg.
* expr.c (copy_blkmode_from_reg): New function.
* expr.h (copy_blkmode_from_reg): New function.
* integrate.c (function_cannot_inline_p): We can inline
these now.
(expand_inline_function): Use copy_blkmode_from_reg
if needed.  Avoid creating BLKmode REGs.
(copy_rtx_and_substitute): Don't try to SUBREG a BLKmode
object.

From-SVN: r22714

gcc/ChangeLog
gcc/calls.c
gcc/expr.c
gcc/expr.h
gcc/integrate.c

index ce607e1509e462d9929b06c9a3e6981c7923b238..f4e7eab7e38951573106ee99f95b48223e6b4c5a 100644 (file)
@@ -1,3 +1,16 @@
+Thu Oct  1 15:56:01 1998  Gavin Romig-Koch  <gavin@cygnus.com>
+
+       * calls.c (expand_call) : Encapsulate code into 
+       copy_blkmode_from_reg.
+       * expr.c (copy_blkmode_from_reg): New function.
+       * expr.h (copy_blkmode_from_reg): New function.
+       * integrate.c (function_cannot_inline_p): We can inline
+       these now.
+       (expand_inline_function): Use copy_blkmode_from_reg
+       if needed.  Avoid creating BLKmode REGs.
+       (copy_rtx_and_substitute): Don't try to SUBREG a BLKmode
+       object.
+
 Thu Oct  1 10:42:27 1998  Nick Clifton  <nickc@cygnus.com>
 
        * c-pragma.c: Add support for HANDLE_PRAGMA_PACK and
index 728d6d68a5d79fde166607dca1d4bf4c16586d85..2bddc2a32a1d74f18774ca92a39a480c7773bb0d 100644 (file)
@@ -2105,75 +2105,7 @@ expand_call (exp, target, ignore)
        when function inlining is being done.  */
     emit_move_insn (target, valreg);
   else if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
-    {
-      /* Some machines (the PA for example) want to return all small
-        structures in registers regardless of the structure's alignment.
-        
-        Deal with them explicitly by copying from the return registers
-        into the target MEM locations.  */
-      int bytes = int_size_in_bytes (TREE_TYPE (exp));
-      rtx src = NULL, dst = NULL;
-      int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (exp)), BITS_PER_WORD);
-      int bitpos, xbitpos, big_endian_correction = 0;
-      
-      if (target == 0)
-       {
-         target = assign_stack_temp (BLKmode, bytes, 0);
-         MEM_IN_STRUCT_P (target) = AGGREGATE_TYPE_P (TREE_TYPE (exp));
-         preserve_temp_slots (target);
-       }
-
-      /* This code assumes valreg is at least a full word.  If it isn't,
-        copy it into a new pseudo which is a full word.  */
-      if (GET_MODE (valreg) != BLKmode
-         && GET_MODE_SIZE (GET_MODE (valreg)) < UNITS_PER_WORD)
-       valreg = convert_to_mode (word_mode, valreg,
-                                 TREE_UNSIGNED (TREE_TYPE (exp)));
-
-      /* Structures whose size is not a multiple of a word are aligned
-        to the least significant byte (to the right).  On a BYTES_BIG_ENDIAN
-        machine, this means we must skip the empty high order bytes when
-        calculating the bit offset.  */
-      if (BYTES_BIG_ENDIAN && bytes % UNITS_PER_WORD)
-       big_endian_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
-                                                 * BITS_PER_UNIT));
-
-      /* Copy the structure BITSIZE bites at a time.
-
-        We could probably emit more efficient code for machines
-        which do not use strict alignment, but it doesn't seem
-        worth the effort at the current time.  */
-      for (bitpos = 0, xbitpos = big_endian_correction;
-          bitpos < bytes * BITS_PER_UNIT;
-          bitpos += bitsize, xbitpos += bitsize)
-       {
-
-         /* We need a new source operand each time xbitpos is on a 
-            word boundary and when xbitpos == big_endian_correction
-            (the first time through).  */
-         if (xbitpos % BITS_PER_WORD == 0
-             || xbitpos == big_endian_correction)
-           src = operand_subword_force (valreg,
-                                        xbitpos / BITS_PER_WORD, 
-                                        BLKmode);
-
-         /* We need a new destination operand each time bitpos is on
-            a word boundary.  */
-         if (bitpos % BITS_PER_WORD == 0)
-           dst = operand_subword (target, bitpos / BITS_PER_WORD, 1, BLKmode);
-             
-         /* Use xbitpos for the source extraction (right justified) and
-            xbitpos for the destination store (left justified).  */
-         store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, word_mode,
-                          extract_bit_field (src, bitsize,
-                                             xbitpos % BITS_PER_WORD, 1,
-                                             NULL_RTX, word_mode,
-                                             word_mode,
-                                             bitsize / BITS_PER_UNIT,
-                                             BITS_PER_WORD),
-                          bitsize / BITS_PER_UNIT, BITS_PER_WORD);
-       }
-    }
+    target = copy_blkmode_from_reg (target, valreg, TREE_TYPE (exp));
   else
     target = copy_to_reg (valreg);
 
index 3582f5b9124f23933ddb06b0e5ee48420bb7b7f7..445f151615680486baa1402b460fc4690493ae01 100644 (file)
@@ -2064,6 +2064,88 @@ emit_group_store (orig_dst, src, ssize, align)
     emit_move_insn (orig_dst, dst);
 }
 
+/* Generate code to copy a BLKmode object of TYPE out of a
+   set of registers starting with SRCREG into TGTBLK.  If TGTBLK
+   is null, a stack temporary is created.  TGTBLK is returned.
+
+   The primary purpose of this routine is to handle functions
+   that return BLKmode structures in registers.  Some machines
+   (the PA for example) want to return all small structures
+   in registers regardless of the structure's alignment.
+  */
+
+rtx
+copy_blkmode_from_reg(tgtblk,srcreg,type)
+     rtx tgtblk;
+     rtx srcreg;
+     tree type;
+{
+      int bytes = int_size_in_bytes (type);
+      rtx src = NULL, dst = NULL;
+      int bitsize = MIN (TYPE_ALIGN (type), BITS_PER_WORD);
+      int bitpos, xbitpos, big_endian_correction = 0;
+      
+      if (tgtblk == 0)
+       {
+         tgtblk = assign_stack_temp (BLKmode, bytes, 0);
+         MEM_IN_STRUCT_P (tgtblk) = AGGREGATE_TYPE_P (type);
+         preserve_temp_slots (tgtblk);
+       }
+      
+      /* This code assumes srcreg is at least a full word.  If it isn't,
+        copy it into a new pseudo which is a full word.  */
+      if (GET_MODE (srcreg) != BLKmode
+         && GET_MODE_SIZE (GET_MODE (srcreg)) < UNITS_PER_WORD)
+       srcreg = convert_to_mode (word_mode, srcreg,
+                                 TREE_UNSIGNED (type));
+
+      /* Structures whose size is not a multiple of a word are aligned
+        to the least significant byte (to the right).  On a BYTES_BIG_ENDIAN
+        machine, this means we must skip the empty high order bytes when
+        calculating the bit offset.  */
+      if (BYTES_BIG_ENDIAN && bytes % UNITS_PER_WORD)
+       big_endian_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
+                                                 * BITS_PER_UNIT));
+
+      /* Copy the structure BITSIZE bites at a time.
+
+        We could probably emit more efficient code for machines
+        which do not use strict alignment, but it doesn't seem
+        worth the effort at the current time.  */
+      for (bitpos = 0, xbitpos = big_endian_correction;
+          bitpos < bytes * BITS_PER_UNIT;
+          bitpos += bitsize, xbitpos += bitsize)
+       {
+
+         /* We need a new source operand each time xbitpos is on a 
+            word boundary and when xbitpos == big_endian_correction
+            (the first time through).  */
+         if (xbitpos % BITS_PER_WORD == 0
+             || xbitpos == big_endian_correction)
+           src = operand_subword_force (srcreg,
+                                        xbitpos / BITS_PER_WORD, 
+                                        BLKmode);
+
+         /* We need a new destination operand each time bitpos is on
+            a word boundary.  */
+         if (bitpos % BITS_PER_WORD == 0)
+           dst = operand_subword (tgtblk, bitpos / BITS_PER_WORD, 1, BLKmode);
+             
+         /* Use xbitpos for the source extraction (right justified) and
+            xbitpos for the destination store (left justified).  */
+         store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, word_mode,
+                          extract_bit_field (src, bitsize,
+                                             xbitpos % BITS_PER_WORD, 1,
+                                             NULL_RTX, word_mode,
+                                             word_mode,
+                                             bitsize / BITS_PER_UNIT,
+                                             BITS_PER_WORD),
+                          bitsize / BITS_PER_UNIT, BITS_PER_WORD);
+       }
+      return tgtblk;
+}
+
+
 /* Add a USE expression for REG to the (possibly empty) list pointed
    to by CALL_FUSAGE.  REG must denote a hard register.  */
 
index 6d8d22a84d3df229087d0a26355f2411b6300bd3..353e6fdfe46071ec983e4e230e9e0d0e3c11433e 100644 (file)
@@ -732,6 +732,11 @@ extern void emit_group_load PROTO((rtx, rtx, int, int));
    PARALLEL.  */
 extern void emit_group_store PROTO((rtx, rtx, int, int));
 
+#ifdef TREE_CODE
+/* Copy BLKmode object from a set of registers. */
+extern rtx copy_blkmode_from_reg PROTO((rtx,rtx,tree));
+#endif
+
 /* Mark REG as holding a parameter for the next CALL_INSN.  */
 extern void use_reg PROTO((rtx *, rtx));
 /* Mark NREGS consecutive regs, starting at REGNO, as holding parameters
index d3fb05bbbfcf482ae682e601137b5927dfe98dc2..db82e322b064af339d30805c37bad3cf152a244f 100644 (file)
@@ -154,11 +154,6 @@ function_cannot_inline_p (fndecl)
   if (current_function_returns_pcc_struct)
     return "inline functions not supported for this return value type";
 
-  /* We can't inline functions that return BLKmode structures in registers.  */
-  if (TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode
-      && ! aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl))))
-    return "inline functions not supported for this return value type";
-
   /* We can't inline functions that return structures of varying size.  */
   if (int_size_in_bytes (TREE_TYPE (TREE_TYPE (fndecl))) < 0)
     return "function with varying-size return value cannot be inline";
@@ -1804,7 +1799,23 @@ expand_inline_function (fndecl, parms, target, ignore, type,
         Let the combiner substitute the MEM if that is valid.  */
       if (target == 0 || GET_CODE (target) != REG
          || GET_MODE (target) != departing_mode)
+       {
+         /* Don't make BLKmode registers.  If this looks like
+            a BLKmode object being returned in a register, get
+            the mode from that, otherwise abort. */
+         if (departing_mode == BLKmode)
+           {
+             if (REG == GET_CODE (DECL_RTL (DECL_RESULT (fndecl))))
+               {
+                 departing_mode = GET_MODE (DECL_RTL (DECL_RESULT (fndecl)));
+                 arriving_mode = departing_mode;
+               }
+             else
+               abort();
+           }
+             
        target = gen_reg_rtx (departing_mode);
+       }
 
       /* If function's value was promoted before return,
         avoid machine mode mismatch when we substitute INLINE_TARGET.
@@ -2164,6 +2175,12 @@ expand_inline_function (fndecl, parms, target, ignore, type,
 
   emit_line_note (input_filename, lineno);
 
+  /* If the function returns a BLKmode object in a register, copy it
+     out of the temp register into a BLKmode memory object. */
+  if (TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode
+      && ! aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl))))
+    target = copy_blkmode_from_reg (0, target, TREE_TYPE (TREE_TYPE (fndecl)));
+  
   if (structure_value_addr)
     {
       target = gen_rtx_MEM (TYPE_MODE (type),
@@ -2428,12 +2445,13 @@ copy_rtx_and_substitute (orig, map)
            {
              /* This is a reference to the function return value.  If
                 the function doesn't have a return value, error.  If the
-                mode doesn't agree, make a SUBREG.  */
+                mode doesn't agree, and it ain't BLKmode, make a SUBREG.  */
              if (map->inline_target == 0)
                /* Must be unrolling loops or replicating code if we
                   reach here, so return the register unchanged.  */
                return orig;
-             else if (mode != GET_MODE (map->inline_target))
+             else if (GET_MODE (map->inline_target) != BLKmode
+                      && mode != GET_MODE (map->inline_target))
                return gen_lowpart (mode, map->inline_target);
              else
                return map->inline_target;