]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR middle-end/54315 (unnecessary copy of return value for union)
authorEric Botcazou <ebotcazou@adacore.com>
Sat, 20 Oct 2012 21:00:23 +0000 (21:00 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Sat, 20 Oct 2012 21:00:23 +0000 (21:00 +0000)
PR rtl-optimization/54315
* calls.c (expand_call): Don't deal specifically with BLKmode values
returned in naked registers.
* expr.h (copy_blkmode_from_reg): Adjust prototype.
* expr.c (copy_blkmode_from_reg): Rename first parameter into TARGET and
make it required.  Assert that SRCREG hasn't BLKmode.  Add a couple of
short-circuits for common cases and be prepared for sub-word registers.
(expand_assignment): Call copy_blkmode_from_reg for BLKmode values
returned in naked registers.
(store_expr): Likewise.
(store_field): Likewise.

From-SVN: r192641

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

index 0403a90eb45bf2e215dc0f27a289743af7f077f3..7a1aff9b2487876bcd691c2fe932110c7eef3cc4 100644 (file)
@@ -1,3 +1,17 @@
+2012-10-20  Eric Botcazou  <ebotcazou@adacore.com>
+
+       PR rtl-optimization/54315
+       * calls.c (expand_call): Don't deal specifically with BLKmode values
+       returned in naked registers.
+       * expr.h (copy_blkmode_from_reg): Adjust prototype.
+       * expr.c (copy_blkmode_from_reg): Rename first parameter into TARGET and
+       make it required.  Assert that SRCREG hasn't BLKmode.  Add a couple of 
+       short-circuits for common cases and be prepared for sub-word registers.
+       (expand_assignment): Call copy_blkmode_from_reg for BLKmode values
+       returned in naked registers.
+       (store_expr): Likewise.
+       (store_field): Likewise.
+
 2012-10-20  Jan Hubicka  <jh@suse.cz>
 
        * loop-unroll.c (decide_unroll_constant_iterations): Don't
index d4ef639dc10d97a7f537201682d9b33ded9edb5f..64e4b09870cad252bf13aba30cb36e0955b92bd7 100644 (file)
@@ -3327,16 +3327,6 @@ expand_call (tree exp, rtx target, int ignore)
                sibcall_failure = 1;
            }
        }
-      else if (TYPE_MODE (rettype) == BLKmode)
-       {
-         rtx val = valreg;
-         if (GET_MODE (val) != BLKmode)
-           val = avoid_likely_spilled_reg (val);
-         target = copy_blkmode_from_reg (target, val, rettype);
-
-         /* We can not support sibling calls for this case.  */
-         sibcall_failure = 1;
-       }
       else
        target = copy_to_reg (avoid_likely_spilled_reg (valreg));
 
index 8fa19fd5ce131394bbf3a8cab5dd326d77d8d9e0..f00ae6a9eac95e15f7005c9aec2c5129987df1f0 100644 (file)
@@ -2086,39 +2086,23 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
     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.
+/* Copy a BLKmode object of TYPE out of a register SRCREG into TARGET.
 
-   The 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.  */
+   This is used on targets that return BLKmode values in registers.  */
 
-rtx
-copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
+void
+copy_blkmode_from_reg (rtx target, rtx srcreg, tree type)
 {
   unsigned HOST_WIDE_INT bytes = int_size_in_bytes (type);
   rtx src = NULL, dst = NULL;
   unsigned HOST_WIDE_INT bitsize = MIN (TYPE_ALIGN (type), BITS_PER_WORD);
   unsigned HOST_WIDE_INT bitpos, xbitpos, padding_correction = 0;
+  enum machine_mode mode = GET_MODE (srcreg);
+  enum machine_mode tmode = GET_MODE (target);
   enum machine_mode copy_mode;
 
-  if (tgtblk == 0)
-    {
-      tgtblk = assign_temp (build_qualified_type (type,
-                                                 (TYPE_QUALS (type)
-                                                  | TYPE_QUAL_CONST)),
-                           1, 1);
-      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, TYPE_UNSIGNED (type));
+  /* BLKmode registers created in the back-end shouldn't have survived.  */
+  gcc_assert (mode != BLKmode);
 
   /* If the structure doesn't take up a whole number of words, see whether
      SRCREG is padded on the left or on the right.  If it's on the left,
@@ -2136,22 +2120,54 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
     padding_correction
       = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT));
 
+  /* We can use a single move if we have an exact mode for the size.  */
+  else if (MEM_P (target)
+          && (!SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target))
+              || MEM_ALIGN (target) >= GET_MODE_ALIGNMENT (mode))
+          && bytes == GET_MODE_SIZE (mode))
+  {
+    emit_move_insn (adjust_address (target, mode, 0), srcreg);
+    return;
+  }
+
+  /* And if we additionally have the same mode for a register.  */
+  else if (REG_P (target)
+          && GET_MODE (target) == mode
+          && bytes == GET_MODE_SIZE (mode))
+  {
+    emit_move_insn (target, srcreg);
+    return;
+  }
+
+  /* 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_SIZE (mode) < UNITS_PER_WORD)
+    {
+      srcreg = convert_to_mode (word_mode, srcreg, TYPE_UNSIGNED (type));
+      mode = word_mode;
+    }
+
   /* Copy the structure BITSIZE bits at a time.  If the target lives in
      memory, take care of not reading/writing past its end by selecting
      a copy mode suited to BITSIZE.  This should always be possible given
      how it is computed.
 
+     If the target lives in register, make sure not to select a copy mode
+     larger than the mode of the register.
+
      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.  */
 
   copy_mode = word_mode;
-  if (MEM_P (tgtblk))
+  if (MEM_P (target))
     {
       enum machine_mode mem_mode = mode_for_size (bitsize, MODE_INT, 1);
       if (mem_mode != BLKmode)
        copy_mode = mem_mode;
     }
+  else if (REG_P (target) && GET_MODE_BITSIZE (tmode) < BITS_PER_WORD)
+    copy_mode = tmode;
 
   for (bitpos = 0, xbitpos = padding_correction;
        bitpos < bytes * BITS_PER_UNIT;
@@ -2160,15 +2176,15 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
       /* We need a new source operand each time xbitpos is on a
         word boundary and when xbitpos == padding_correction
         (the first time through).  */
-      if (xbitpos % BITS_PER_WORD == 0
-         || xbitpos == padding_correction)
-       src = operand_subword_force (srcreg, xbitpos / BITS_PER_WORD,
-                                    GET_MODE (srcreg));
+      if (xbitpos % BITS_PER_WORD == 0 || xbitpos == padding_correction)
+       src = operand_subword_force (srcreg, xbitpos / BITS_PER_WORD, mode);
 
       /* 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);
+      if (REG_P (target) && GET_MODE_BITSIZE (tmode) < BITS_PER_WORD)
+       dst = target;
+      else if (bitpos % BITS_PER_WORD == 0)
+       dst = operand_subword (target, bitpos / BITS_PER_WORD, 1, tmode);
 
       /* Use xbitpos for the source extraction (right justified) and
         bitpos for the destination store (left justified).  */
@@ -2177,8 +2193,6 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
                                          xbitpos % BITS_PER_WORD, 1, false,
                                          NULL_RTX, copy_mode, copy_mode));
     }
-
-  return tgtblk;
 }
 
 /* Copy BLKmode value SRC into a register of mode MODE.  Return the
@@ -4883,7 +4897,12 @@ expand_assignment (tree to, tree from, bool nontemporal)
        emit_group_store (to_rtx, value, TREE_TYPE (from),
                          int_size_in_bytes (TREE_TYPE (from)));
       else if (GET_MODE (to_rtx) == BLKmode)
-       emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL);
+       {
+         if (REG_P (value))
+           copy_blkmode_from_reg (to_rtx, value, TREE_TYPE (from));
+         else
+           emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL);
+       }
       else
        {
          if (POINTER_TYPE_P (TREE_TYPE (to)))
@@ -5225,21 +5244,26 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
         supposed to be bit-copied or bit-initialized.  */
       && expr_size (exp) != const0_rtx)
     {
-      if (GET_MODE (temp) != GET_MODE (target)
-         && GET_MODE (temp) != VOIDmode)
+      if (GET_MODE (temp) != GET_MODE (target) && GET_MODE (temp) != VOIDmode)
        {
-         int unsignedp = TYPE_UNSIGNED (TREE_TYPE (exp));
-         if (GET_MODE (target) == BLKmode
-             && GET_MODE (temp) == BLKmode)
-           emit_block_move (target, temp, expr_size (exp),
-                            (call_param_p
-                             ? BLOCK_OP_CALL_PARM
-                             : BLOCK_OP_NORMAL));
-         else if (GET_MODE (target) == BLKmode)
-           store_bit_field (target, INTVAL (expr_size (exp)) * BITS_PER_UNIT,
-                            0, 0, 0, GET_MODE (temp), temp);
+         if (GET_MODE (target) == BLKmode)
+           {
+             if (REG_P (temp))
+               {
+                 if (TREE_CODE (exp) == CALL_EXPR)
+                   copy_blkmode_from_reg (target, temp, TREE_TYPE (exp));
+                 else
+                   store_bit_field (target,
+                                    INTVAL (expr_size (exp)) * BITS_PER_UNIT,
+                                    0, 0, 0, GET_MODE (temp), temp);
+               }
+             else
+               emit_block_move (target, temp, expr_size (exp),
+                                (call_param_p
+                                 ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
+           }
          else
-           convert_move (target, temp, unsignedp);
+           convert_move (target, temp, TYPE_UNSIGNED (TREE_TYPE (exp)));
        }
 
       else if (GET_MODE (temp) == BLKmode && TREE_CODE (exp) == STRING_CST)
@@ -6328,7 +6352,8 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
      twice, once with emit_move_insn and once via store_field.  */
 
   if (mode == BLKmode
-      && (REG_P (target) || GET_CODE (target) == SUBREG))
+      && (REG_P (target) || GET_CODE (target) == SUBREG)
+      && TREE_CODE (exp) != CALL_EXPR)
     {
       rtx object = assign_temp (type, 1, 1);
       rtx blk_object = adjust_address (object, BLKmode, 0);
@@ -6477,6 +6502,16 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
          temp = temp_target;
        }
 
+      /* Handle calls that return BLKmode values in registers.  */
+      else if (mode == BLKmode
+              && REG_P (temp)
+              && TREE_CODE (exp) == CALL_EXPR)
+       {
+         rtx temp_target = gen_reg_rtx (GET_MODE (temp));
+         copy_blkmode_from_reg (temp_target, temp, TREE_TYPE (exp));
+         temp = temp_target;
+       }
+
       /* Store the value in the bitfield.  */
       store_bit_field (target, bitsize, bitpos,
                       bitregion_start, bitregion_end,
index 562ffe03aca68e503f8cfa3f382f8c0574e25ccd..0f5e8541fb07e5c35c5c208777e5edfd9f6f328e 100644 (file)
@@ -335,7 +335,7 @@ extern rtx emit_group_move_into_temps (rtx);
 extern void emit_group_store (rtx, rtx, tree, int);
 
 /* Copy BLKmode object from a set of registers.  */
-extern rtx copy_blkmode_from_reg (rtx, rtx, tree);
+extern void copy_blkmode_from_reg (rtx, rtx, tree);
 
 /* Mark REG as holding a parameter for the next CALL_INSN.
    Mode is TYPE_MODE of the non-promoted parameter, or VOIDmode.  */