diff options
author | Uros Bizjak <uros@gcc.gnu.org> | 2011-08-09 19:59:20 +0200 |
---|---|---|
committer | Uros Bizjak <uros@gcc.gnu.org> | 2011-08-09 19:59:20 +0200 |
commit | 2813f1b15f9629c053c8c8b590cc0632689812a2 (patch) | |
tree | daa5df2761c54c3ffaafaa3cd31415119564018f | |
parent | c6412d86762ea3c31654c4c72b5e7ef86e66d90e (diff) | |
download | gcc-2813f1b15f9629c053c8c8b590cc0632689812a2.zip gcc-2813f1b15f9629c053c8c8b590cc0632689812a2.tar.gz gcc-2813f1b15f9629c053c8c8b590cc0632689812a2.tar.bz2 |
i386.c (ix86_emit_i387_round): New function.
* config/i386/i386.c (ix86_emit_i387_round): New function.
* config/i386/i386-protos.h (ix86_emit_i387_round): Declare.
* config/i386/i386.md (round<mode>2): Use X87MODEF mode iterator.
Use ix86_emit_i387_round to expand round function for i387 math.
(lround<X87MODEF:mode><SWI248x:mode>2): Use X87MODEF mode iterator.
Use ix86_emit_i387_round to expand {l,ll}round function for i387 math.
From-SVN: r177605
-rw-r--r-- | gcc/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/config/i386/i386-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 135 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 57 |
4 files changed, 188 insertions, 17 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a81bf08..1816b2d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,8 +1,16 @@ +2011-08-09 Uros Bizjak <ubizjak@gmail.com> + + * config/i386/i386.c (ix86_emit_i387_round): New function. + * config/i386/i386-protos.h (ix86_emit_i387_round): Declare. + * config/i386/i386.md (round<mode>2): Use X87MODEF mode iterator. + Use ix86_emit_i387_round to expand round function for i387 math. + (lround<X87MODEF:mode><SWI248x:mode>2): Use X87MODEF mode iterator. + Use ix86_emit_i387_round to expand {l,ll}round function for i387 math. + 2011-08-09 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> * config/sync.c: Move to ../libgcc. - * Makefile.in (libgcc.mvars): Remove LIBGCC_SYNC, - LIBGCC_SYNC_CFLAGS. + * Makefile.in (libgcc.mvars): Remove LIBGCC_SYNC, LIBGCC_SYNC_CFLAGS. * config/mips/t-libgcc-mips16 (LIBGCC_SYNC, LIBGCC_SYNC_CFLAGS): Remove. diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 83f39dc..c3eb150 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -163,6 +163,7 @@ extern void x86_emit_floatuns (rtx [2]); extern void ix86_emit_fp_unordered_jump (rtx); extern void ix86_emit_i387_log1p (rtx, rtx); +extern void ix86_emit_i387_round (rtx, rtx); extern void ix86_emit_swdivsf (rtx, rtx, rtx, enum machine_mode); extern void ix86_emit_swsqrtsf (rtx, rtx, enum machine_mode, bool); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index c9781e1..05dd57c 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -28260,7 +28260,7 @@ ix86_secondary_reload (bool in_p, rtx x, reg_class_t rclass, sri->icode = (in_p ? CODE_FOR_reload_noff_load : CODE_FOR_reload_noff_store); - /* Add the cost of move to a temporary. */ + /* Add the cost of moving address to a temporary. */ sri->extra_cost = 1; return NO_REGS; @@ -31731,6 +31731,139 @@ void ix86_emit_i387_log1p (rtx op0, rtx op1) emit_label (label2); } +/* Emit code for round calculation. */ +void ix86_emit_i387_round (rtx op0, rtx op1) +{ + enum machine_mode inmode = GET_MODE (op1); + enum machine_mode outmode = GET_MODE (op0); + rtx e1, e2, res, tmp, tmp1, half; + rtx scratch = gen_reg_rtx (HImode); + rtx flags = gen_rtx_REG (CCNOmode, FLAGS_REG); + rtx jump_label = gen_label_rtx (); + rtx insn; + rtx (*gen_abs) (rtx, rtx); + rtx (*gen_neg) (rtx, rtx); + + switch (inmode) + { + case SFmode: + gen_abs = gen_abssf2; + break; + case DFmode: + gen_abs = gen_absdf2; + break; + case XFmode: + gen_abs = gen_absxf2; + break; + default: + gcc_unreachable (); + } + + switch (outmode) + { + case SFmode: + gen_neg = gen_negsf2; + break; + case DFmode: + gen_neg = gen_negdf2; + break; + case XFmode: + gen_neg = gen_negxf2; + break; + case HImode: + gen_neg = gen_neghi2; + break; + case SImode: + gen_neg = gen_negsi2; + break; + case DImode: + gen_neg = gen_negdi2; + break; + default: + gcc_unreachable (); + } + + e1 = gen_reg_rtx (inmode); + e2 = gen_reg_rtx (inmode); + res = gen_reg_rtx (outmode); + + half = CONST_DOUBLE_FROM_REAL_VALUE (dconsthalf, inmode); + + /* round(a) = sgn(a) * floor(fabs(a) + 0.5) */ + + /* scratch = fxam(op1) */ + emit_insn (gen_rtx_SET (VOIDmode, scratch, + gen_rtx_UNSPEC (HImode, gen_rtvec (1, op1), + UNSPEC_FXAM))); + /* e1 = fabs(op1) */ + emit_insn (gen_abs (e1, op1)); + + /* e2 = e1 + 0.5 */ + half = force_reg (inmode, half); + emit_insn (gen_rtx_SET (VOIDmode, e2, + gen_rtx_PLUS (inmode, e1, half))); + + /* res = floor(e2) */ + if (inmode != XFmode) + { + tmp1 = gen_reg_rtx (XFmode); + + emit_insn (gen_rtx_SET (VOIDmode, tmp1, + gen_rtx_FLOAT_EXTEND (XFmode, e2))); + } + else + tmp1 = e2; + + switch (outmode) + { + case SFmode: + case DFmode: + { + rtx tmp0 = gen_reg_rtx (XFmode); + + emit_insn (gen_frndintxf2_floor (tmp0, tmp1)); + + emit_insn (gen_rtx_SET (VOIDmode, res, + gen_rtx_UNSPEC (outmode, gen_rtvec (1, tmp0), + UNSPEC_TRUNC_NOOP))); + } + break; + case XFmode: + emit_insn (gen_frndintxf2_floor (res, tmp1)); + break; + case HImode: + emit_insn (gen_lfloorxfhi2 (res, tmp1)); + break; + case SImode: + emit_insn (gen_lfloorxfsi2 (res, tmp1)); + break; + case DImode: + emit_insn (gen_lfloorxfdi2 (res, tmp1)); + break; + default: + gcc_unreachable (); + } + + /* flags = signbit(a) */ + emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x02))); + + /* if (flags) then res = -res */ + tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, + gen_rtx_EQ (VOIDmode, flags, const0_rtx), + gen_rtx_LABEL_REF (VOIDmode, jump_label), + pc_rtx); + insn = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); + predict_jump (REG_BR_PROB_BASE * 50 / 100); + JUMP_LABEL (insn) = jump_label; + + emit_insn (gen_neg (res, res)); + + emit_label (jump_label); + LABEL_NUSES (jump_label) = 1; + + emit_move_insn (op0, res); +} + /* Output code to perform a Newton-Rhapson approximation of a single precision floating point divide [http://en.wikipedia.org/wiki/N-th_root_algorithm]. */ diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 9dc5c85..784de1a 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -14396,17 +14396,31 @@ }) (define_expand "round<mode>2" - [(match_operand:MODEF 0 "register_operand" "") - (match_operand:MODEF 1 "nonimmediate_operand" "")] - "SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH - && !flag_trapping_math && !flag_rounding_math" + [(match_operand:X87MODEF 0 "register_operand" "") + (match_operand:X87MODEF 1 "nonimmediate_operand" "")] + "(TARGET_USE_FANCY_MATH_387 + && (!(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH) + || TARGET_MIX_SSE_I387) + && flag_unsafe_math_optimizations) + || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH + && !flag_trapping_math && !flag_rounding_math)" { if (optimize_insn_for_size_p ()) FAIL; - if (TARGET_64BIT || (<MODE>mode != DFmode)) - ix86_expand_round (operand0, operand1); + + if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH + && !flag_trapping_math && !flag_rounding_math) + { + if (TARGET_64BIT || (<MODE>mode != DFmode)) + ix86_expand_round (operands[0], operands[1]); + else + ix86_expand_rounddf_32 (operands[0], operands[1]); + } else - ix86_expand_rounddf_32 (operand0, operand1); + { + operands[1] = force_reg (<MODE>mode, operands[1]); + ix86_emit_i387_round (operands[0], operands[1]); + } DONE; }) @@ -14542,16 +14556,31 @@ "SSE_FLOAT_MODE_P (<MODEF:MODE>mode) && TARGET_SSE_MATH && ((<SWI48x:MODE>mode != DImode) || TARGET_64BIT)") -(define_expand "lround<MODEF:mode><SWI48x:mode>2" - [(match_operand:SWI48x 0 "nonimmediate_operand" "") - (match_operand:MODEF 1 "register_operand" "")] - "SSE_FLOAT_MODE_P (<MODEF:MODE>mode) && TARGET_SSE_MATH - && ((<SWI48x:MODE>mode != DImode) || TARGET_64BIT) - && !flag_trapping_math && !flag_rounding_math" +(define_expand "lround<X87MODEF:mode><SWI248x:mode>2" + [(match_operand:SWI248x 0 "nonimmediate_operand" "") + (match_operand:X87MODEF 1 "register_operand" "")] + "(TARGET_USE_FANCY_MATH_387 + && (!(SSE_FLOAT_MODE_P (<X87MODEF:MODE>mode) && TARGET_SSE_MATH) + || TARGET_MIX_SSE_I387) + && flag_unsafe_math_optimizations) + || (SSE_FLOAT_MODE_P (<X87MODEF:MODE>mode) && TARGET_SSE_MATH + && <SWI248x:MODE>mode != HImode + && ((<SWI248x:MODE>mode != DImode) || TARGET_64BIT) + && !flag_trapping_math && !flag_rounding_math)" { if (optimize_insn_for_size_p ()) FAIL; - ix86_expand_lround (operand0, operand1); + + if (SSE_FLOAT_MODE_P (<X87MODEF:MODE>mode) && TARGET_SSE_MATH + && <SWI248x:MODE>mode != HImode + && ((<SWI248x:MODE>mode != DImode) || TARGET_64BIT) + && !flag_trapping_math && !flag_rounding_math) + ix86_expand_lround (operand0, operand1); + else + { + operands[0] = force_reg (<SWI248x:MODE>mode, operands[0]); + ix86_emit_i387_round (operands[0], operands[1]); + } DONE; }) |