aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2015-11-19 08:17:21 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2015-11-19 08:17:21 +0000
commitee1326921d7cb8645bed87b2d9b71f1f74eb6605 (patch)
tree5c6549eb554dd14ad1e4a4f1834c2aeeb51136d4
parentd0eccfcdc30257a23ce82041a035626350fa421f (diff)
downloadgcc-ee1326921d7cb8645bed87b2d9b71f1f74eb6605.zip
gcc-ee1326921d7cb8645bed87b2d9b71f1f74eb6605.tar.gz
gcc-ee1326921d7cb8645bed87b2d9b71f1f74eb6605.tar.bz2
PR 68393: Handle SUBREG_PROMOTED_VAR_P in expand_direct_optab_fn
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
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/internal-fn.c30
2 files changed, 29 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 26ddccc..f37ad25 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index df3b7dc..bc77bdc3 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -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);
+ }
}
}