PR 68393: Handle SUBREG_PROMOTED_VAR_P in expand_direct_optab_fn
authorRichard Sandiford <richard.sandiford@arm.com>
Thu, 19 Nov 2015 08:17:21 +0000 (08:17 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Thu, 19 Nov 2015 08:17:21 +0000 (08:17 +0000)
Do the usual dance when assigning to SUBREG_PROMOTED_VAR_P destinations:
first convert to the outer mode, then extend to the inner mode.

Tested that it fixes the powerpc64le-linux-gnu breakage.  Also tested
on x86_64-linux-gnu and powerpc64-linux-gnu.

gcc/
PR bootstrap/68393
* internal-fn.c (expand_direct_optab_fn): Handle SUBREG_PROMOTED_VAR_P
destinations.

From-SVN: r230590

gcc/ChangeLog
gcc/internal-fn.c

index 26ddcccfbd493b865ec0ddaee6595ba9c3ff2215..f37ad250cb4913dcdf8c6ee6565645786502b2a9 100644 (file)
@@ -1,3 +1,9 @@
+2015-11-19  Richard Sandiford  <richard.sandiford@arm.com>
+
+       PR bootstrap/68393
+       * internal-fn.c (expand_direct_optab_fn): Handle SUBREG_PROMOTED_VAR_P
+       destinations.
+
 2015-11-18  Jeff Law  <law@redhat.com>
 
        PR tree-optimization/68198
index df3b7dc6720b67e3527805cfca9a018d1bcb65ae..bc77bdc3b55e96401a72400d01f2510e55705362 100644 (file)
@@ -2124,14 +2124,30 @@ expand_direct_optab_fn (internal_fn fn, gcall *stmt, direct_optab optab,
   expand_insn (icode, nargs + 1, ops);
   if (!rtx_equal_p (lhs_rtx, ops[0].value))
     {
-      if (INTEGRAL_TYPE_P (lhs_type))
-       /* Convert the operand to the required type, which is useful
-          for things that return an int regardless of the size of
-          the input.  If the value produced by the instruction is
-          smaller than required, assume that it is signed.  */
-       convert_move (lhs_rtx, ops[0].value, 0);
-      else
+      /* If the return value has an integral type, convert the instruction
+        result to that type.  This is useful for things that return an
+        int regardless of the size of the input.  If the instruction result
+        is smaller than required, assume that it is signed.
+
+        If the return value has a nonintegral type, its mode must match
+        the instruction result.  */
+      if (GET_CODE (lhs_rtx) == SUBREG && SUBREG_PROMOTED_VAR_P (lhs_rtx))
+       {
+         /* If this is a scalar in a register that is stored in a wider
+            mode than the declared mode, compute the result into its
+            declared mode and then convert to the wider mode.  */
+         gcc_checking_assert (INTEGRAL_TYPE_P (lhs_type));
+         rtx tmp = convert_to_mode (GET_MODE (lhs_rtx), ops[0].value, 0);
+         convert_move (SUBREG_REG (lhs_rtx), tmp,
+                       SUBREG_PROMOTED_SIGN (lhs_rtx));
+       }
+      else if (GET_MODE (lhs_rtx) == GET_MODE (ops[0].value))
        emit_move_insn (lhs_rtx, ops[0].value);
+      else
+       {
+         gcc_checking_assert (INTEGRAL_TYPE_P (lhs_type));
+         convert_move (lhs_rtx, ops[0].value, 0);
+       }
     }
 }