i386.c (ix86_emit_i387_round): New function.
authorUros Bizjak <uros@gcc.gnu.org>
Tue, 9 Aug 2011 17:59:20 +0000 (19:59 +0200)
committerUros Bizjak <uros@gcc.gnu.org>
Tue, 9 Aug 2011 17:59:20 +0000 (19:59 +0200)
* 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

gcc/ChangeLog
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/i386.md

index a81bf0877f6c37812139de773179e885f749793e..1816b2d8971792368d1409fc9a5f472932b366f9 100644 (file)
@@ -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.
 
index 83f39dcc78489ee6c7a2f90233391f1081c62216..c3eb150fbb942ef07b83c7a416d56f0b3cf6ddeb 100644 (file)
@@ -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);
 
index c9781e147a52d79ad748d9dc88956be69c6c2822..05dd57c7ece3ae372d77900371b539d2721ff75d 100644 (file)
@@ -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].  */
 
index 9dc5c8539800820df7eb5d9bb5a7e9a879ff3ebb..784de1a06511cc930a92f531f869c1c2fd0656da 100644 (file)
 })
 
 (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;
 })
 
   "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;
 })