diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/optabs.c | 43 |
2 files changed, 33 insertions, 18 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 36cfad0..c4407d6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -2,6 +2,14 @@ Alan Hayward <alan.hayward@arm.com> David Sherwood <david.sherwood@arm.com> + * optabs.c (expand_float): Explicitly check for scalars before + using a branching expansion. + (expand_fix): Likewise. + +2017-08-30 Richard Sandiford <richard.sandiford@linaro.org> + Alan Hayward <alan.hayward@arm.com> + David Sherwood <david.sherwood@arm.com> + * expr.c (convert_mode): Split scalar handling out into... (convert_mode_scalar): ...this new function. Treat the modes as scalar_modes. diff --git a/gcc/optabs.c b/gcc/optabs.c index 49f35b0..d3ceaba 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -4637,6 +4637,7 @@ expand_float (rtx to, rtx from, int unsignedp) { enum insn_code icode; rtx target = to; + scalar_mode from_mode, to_mode; machine_mode fmode, imode; bool can_do_signed = false; @@ -4686,7 +4687,10 @@ expand_float (rtx to, rtx from, int unsignedp) /* Unsigned integer, and no way to convert directly. Convert as signed, then unconditionally adjust the result. */ - if (unsignedp && can_do_signed) + if (unsignedp + && can_do_signed + && is_a <scalar_mode> (GET_MODE (to), &to_mode) + && is_a <scalar_mode> (GET_MODE (from), &from_mode)) { rtx_code_label *label = gen_label_rtx (); rtx temp; @@ -4696,19 +4700,19 @@ expand_float (rtx to, rtx from, int unsignedp) least as wide as the target. Using FMODE will avoid rounding woes with unsigned values greater than the signed maximum value. */ - FOR_EACH_MODE_FROM (fmode, GET_MODE (to)) - if (GET_MODE_PRECISION (GET_MODE (from)) < GET_MODE_BITSIZE (fmode) - && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing) + FOR_EACH_MODE_FROM (fmode, to_mode) + if (GET_MODE_PRECISION (from_mode) < GET_MODE_BITSIZE (fmode) + && can_float_p (fmode, from_mode, 0) != CODE_FOR_nothing) break; if (fmode == VOIDmode) { /* There is no such mode. Pretend the target is wide enough. */ - fmode = GET_MODE (to); + fmode = to_mode; /* Avoid double-rounding when TO is narrower than FROM. */ if ((significand_size (fmode) + 1) - < GET_MODE_PRECISION (GET_MODE (from))) + < GET_MODE_PRECISION (from_mode)) { rtx temp1; rtx_code_label *neglabel = gen_label_rtx (); @@ -4720,7 +4724,7 @@ expand_float (rtx to, rtx from, int unsignedp) || GET_MODE (target) != fmode) target = gen_reg_rtx (fmode); - imode = GET_MODE (from); + imode = from_mode; do_pending_stack_adjust (); /* Test whether the sign bit is set. */ @@ -4760,7 +4764,7 @@ expand_float (rtx to, rtx from, int unsignedp) /* If we are about to do some arithmetic to correct for an unsigned operand, do it in a pseudo-register. */ - if (GET_MODE (to) != fmode + if (to_mode != fmode || !REG_P (to) || REGNO (to) < FIRST_PSEUDO_REGISTER) target = gen_reg_rtx (fmode); @@ -4771,11 +4775,11 @@ expand_float (rtx to, rtx from, int unsignedp) correct its value by 2**bitwidth. */ do_pending_stack_adjust (); - emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from), + emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, from_mode, 0, label); - real_2expN (&offset, GET_MODE_PRECISION (GET_MODE (from)), fmode); + real_2expN (&offset, GET_MODE_PRECISION (from_mode), fmode); temp = expand_binop (fmode, add_optab, target, const_double_from_real_value (offset, fmode), target, 0, OPTAB_LIB_WIDEN); @@ -4903,11 +4907,14 @@ expand_fix (rtx to, rtx from, int unsignedp) 2^63. The subtraction of 2^63 should not generate any rounding as it simply clears out that bit. The rest is trivial. */ - if (unsignedp && GET_MODE_PRECISION (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT) + scalar_int_mode to_mode; + if (unsignedp + && is_a <scalar_int_mode> (GET_MODE (to), &to_mode) + && HWI_COMPUTABLE_MODE_P (to_mode)) FOR_EACH_MODE_FROM (fmode, GET_MODE (from)) - if (CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0, &must_trunc) + if (CODE_FOR_nothing != can_fix_p (to_mode, fmode, 0, &must_trunc) && (!DECIMAL_FLOAT_MODE_P (fmode) - || GET_MODE_BITSIZE (fmode) > GET_MODE_PRECISION (GET_MODE (to)))) + || GET_MODE_BITSIZE (fmode) > GET_MODE_PRECISION (to_mode))) { int bitsize; REAL_VALUE_TYPE offset; @@ -4915,7 +4922,7 @@ expand_fix (rtx to, rtx from, int unsignedp) rtx_code_label *lab1, *lab2; rtx_insn *insn; - bitsize = GET_MODE_PRECISION (GET_MODE (to)); + bitsize = GET_MODE_PRECISION (to_mode); real_2expN (&offset, bitsize - 1, fmode); limit = const_double_from_real_value (offset, fmode); lab1 = gen_label_rtx (); @@ -4941,10 +4948,10 @@ expand_fix (rtx to, rtx from, int unsignedp) target = expand_binop (GET_MODE (from), sub_optab, from, limit, NULL_RTX, 0, OPTAB_LIB_WIDEN); expand_fix (to, target, 0); - target = expand_binop (GET_MODE (to), xor_optab, to, + target = expand_binop (to_mode, xor_optab, to, gen_int_mode (HOST_WIDE_INT_1 << (bitsize - 1), - GET_MODE (to)), + to_mode), to, 1, OPTAB_LIB_WIDEN); if (target != to) @@ -4952,12 +4959,12 @@ expand_fix (rtx to, rtx from, int unsignedp) emit_label (lab2); - if (optab_handler (mov_optab, GET_MODE (to)) != CODE_FOR_nothing) + if (optab_handler (mov_optab, to_mode) != CODE_FOR_nothing) { /* Make a place for a REG_NOTE and add it. */ insn = emit_move_insn (to, to); set_dst_reg_note (insn, REG_EQUAL, - gen_rtx_fmt_e (UNSIGNED_FIX, GET_MODE (to), + gen_rtx_fmt_e (UNSIGNED_FIX, to_mode, copy_rtx (from)), to); } |