diff options
author | Richard Sandiford <richard.sandiford@arm.com> | 2015-11-19 08:17:21 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2015-11-19 08:17:21 +0000 |
commit | ee1326921d7cb8645bed87b2d9b71f1f74eb6605 (patch) | |
tree | 5c6549eb554dd14ad1e4a4f1834c2aeeb51136d4 /gcc | |
parent | d0eccfcdc30257a23ce82041a035626350fa421f (diff) | |
download | gcc-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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/internal-fn.c | 30 |
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); + } } } |