From 6e858d450b5a9774494ce68c5084f7dc9a9d2138 Mon Sep 17 00:00:00 2001
From: Uros Bizjak <uros@kss-loka.si>
Date: Tue, 29 Mar 2005 07:46:46 +0200
Subject: [PATCH] reg-stack.c (subst_stack_regs_pat): Handle <UNSPEC_FIST>
 case.

	* reg-stack.c (subst_stack_regs_pat): Handle <UNSPEC_FIST> case.
	* config/i386/i386.c (output_fix_trunc): Add new round_mode
	variable.  Output "fldcw" depending on round_mode.
	* config/i386/i386.md (UNSPEC_FIST): New.
	(fistdi2, fistdi2_with_temp, fist<mode>2, fist<mode>2_with_temp):
	New isns patterns to implement lrint and llrint built-ins as x87
	intrinsic function.
	(fistdi2, fist<mode>2 splitters): New splitters.
	(lrint<mode>2): New expanders.

From-SVN: r97151
---
 gcc/ChangeLog           |  12 +++++
 gcc/config/i386/i386.c  |   7 ++-
 gcc/config/i386/i386.md | 109 +++++++++++++++++++++++++++++++++++++++-
 gcc/reg-stack.c         |  21 ++++++++
 4 files changed, 146 insertions(+), 3 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9d62a101b156..5ba2bc665a92 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+2005-03-29  Uros Bizjak  <uros@kss-loka.si>
+
+	* reg-stack.c (subst_stack_regs_pat): Handle <UNSPEC_FIST> case.
+	* config/i386/i386.c (output_fix_trunc): Add new round_mode
+	variable.  Output "fldcw" depending on round_mode.
+	* config/i386/i386.md (UNSPEC_FIST): New.
+	(fistdi2, fistdi2_with_temp, fist<mode>2, fist<mode>2_with_temp):
+	New isns patterns to implement lrint and llrint built-ins as x87
+	intrinsic function.
+	(fistdi2, fist<mode>2 splitters): New splitters.
+	(lrint<mode>2): New expanders.
+
 2005-03-28  Ian Lance Taylor  <ian@airs.com>
 
 	* config/arc/arc.c (arc_output_function_epilogue): Pass prescan as
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index e25401738191..1e9165f4412a 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -7287,6 +7287,7 @@ output_fix_trunc (rtx insn, rtx *operands, int fisttp)
 {
   int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
   int dimode_p = GET_MODE (operands[0]) == DImode;
+  int round_mode = get_attr_i387_cw (insn);
 
   /* Jump through a hoop or two for DImode, since the hardware has no
      non-popping instruction.  We used to do this a different way, but
@@ -7304,12 +7305,14 @@ output_fix_trunc (rtx insn, rtx *operands, int fisttp)
       output_asm_insn ("fisttp%z0\t%0", operands);
   else
     {
-      output_asm_insn ("fldcw\t%3", operands);
+      if (round_mode != I387_CW_ANY)
+	output_asm_insn ("fldcw\t%3", operands);
       if (stack_top_dies || dimode_p)
 	output_asm_insn ("fistp%z0\t%0", operands);
       else
 	output_asm_insn ("fist%z0\t%0", operands);
-      output_asm_insn ("fldcw\t%2", operands);
+      if (round_mode != I387_CW_ANY)
+	output_asm_insn ("fldcw\t%2", operands);
     }
 
   return "";
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index e168d112933e..9041cd0b5347 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -119,7 +119,8 @@
    (UNSPEC_FYL2X		66)
    (UNSPEC_FYL2XP1		67)
    (UNSPEC_FRNDINT		68)
-   (UNSPEC_F2XM1		69)
+   (UNSPEC_FIST			69)
+   (UNSPEC_F2XM1		70)
 
    ; x87 Double output FP
    (UNSPEC_SINCOS_COS		80)
@@ -16244,6 +16245,112 @@
   DONE;
 })
 
+(define_insn "fistdi2"
+  [(set (match_operand:DI 0 "memory_operand" "=m")
+	(unspec:DI [(match_operand:XF 1 "register_operand" "f")]
+	 UNSPEC_FIST))
+   (clobber (match_scratch:XF 2 "=&1f"))]
+  "TARGET_USE_FANCY_MATH_387
+   && flag_unsafe_math_optimizations"
+  "* return output_fix_trunc (insn, operands, 0);"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "DI")])
+
+(define_insn "fistdi2_with_temp"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r")
+	(unspec:DI [(match_operand:XF 1 "register_operand" "f,f")]
+	 UNSPEC_FIST))
+   (clobber (match_operand:DI 2 "memory_operand" "=m,m"))
+   (clobber (match_scratch:XF 3 "=&1f,&1f"))]
+  "TARGET_USE_FANCY_MATH_387
+   && flag_unsafe_math_optimizations"
+  "#"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "DI")])
+
+(define_split 
+  [(set (match_operand:DI 0 "register_operand" "")
+	(unspec:DI [(match_operand:XF 1 "register_operand" "")]
+	 UNSPEC_FIST))
+   (clobber (match_operand:DI 2 "memory_operand" ""))
+   (clobber (match_scratch 3 ""))]
+  "reload_completed"
+  [(parallel [(set (match_dup 2) (unspec:DI [(match_dup 1)] UNSPEC_FIST))
+	      (clobber (match_dup 3))])
+   (set (match_dup 0) (match_dup 2))]
+  "")
+
+(define_split 
+  [(set (match_operand:DI 0 "memory_operand" "")
+	(unspec:DI [(match_operand:XF 1 "register_operand" "")]
+	 UNSPEC_FIST))
+   (clobber (match_operand:DI 2 "memory_operand" ""))
+   (clobber (match_scratch 3 ""))]
+  "reload_completed"
+  [(parallel [(set (match_dup 0) (unspec:DI [(match_dup 1)] UNSPEC_FIST))
+	      (clobber (match_dup 3))])]
+  "")
+
+(define_insn "fist<mode>2"
+  [(set (match_operand:X87MODEI12 0 "memory_operand" "=m")
+	(unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f")]
+	 UNSPEC_FIST))]
+  "TARGET_USE_FANCY_MATH_387
+   && flag_unsafe_math_optimizations"
+  "* return output_fix_trunc (insn, operands, 0);"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "fist<mode>2_with_temp"
+  [(set (match_operand:X87MODEI12 0 "nonimmediate_operand" "=m,?r")
+	(unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f,f")]
+	 UNSPEC_FIST))
+   (clobber (match_operand:X87MODEI12 2 "memory_operand" "=m,m"))]
+  "TARGET_USE_FANCY_MATH_387
+   && flag_unsafe_math_optimizations"
+  "#"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "<MODE>")])
+
+(define_split 
+  [(set (match_operand:X87MODEI12 0 "register_operand" "")
+	(unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "")]
+	 UNSPEC_FIST))
+   (clobber (match_operand:X87MODEI12 2 "memory_operand" ""))]
+  "reload_completed"
+  [(set (match_dup 2) (unspec:X87MODEI12 [(match_dup 1)]
+		       UNSPEC_FIST))
+   (set (match_dup 0) (match_dup 2))]
+  "")
+
+(define_split 
+  [(set (match_operand:X87MODEI12 0 "memory_operand" "")
+	(unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "")]
+	 UNSPEC_FIST))
+   (clobber (match_scratch 2 ""))]
+  "reload_completed"
+  [(set (match_dup 0) (unspec:X87MODEI12 [(match_dup 1)]
+		       UNSPEC_FIST))]
+  "")
+
+(define_expand "lrint<mode>2"
+  [(use (match_operand:X87MODEI 0 "nonimmediate_operand" ""))
+   (use (match_operand:XF 1 "register_operand" ""))]
+  "TARGET_USE_FANCY_MATH_387
+   && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387)
+   && flag_unsafe_math_optimizations"
+{
+  if (memory_operand (operands[0], VOIDmode))
+    emit_insn (gen_fist<mode>2 (operands[0], operands[1]));
+  else
+    {
+      operands[2] = assign_386_stack_local (<MODE>mode, 0);
+      emit_insn (gen_fist<mode>2_with_temp (operands[0], operands[1],
+					    operands[2]));
+    }
+  DONE;
+})
+
 (define_insn "frndintxf2_floor"
   [(set (match_operand:XF 0 "register_operand" "=f")
 	(unspec:XF [(match_operand:XF 1 "register_operand" "0")]
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c
index e92e73cbf547..6f58341ba277 100644
--- a/gcc/reg-stack.c
+++ b/gcc/reg-stack.c
@@ -1672,6 +1672,27 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
 	  case UNSPEC:
 	    switch (XINT (pat_src, 1))
 	      {
+	      case UNSPEC_FIST:
+		/* These insns only operate on the top of the stack.  */
+
+		src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+		emit_swap_insn (insn, regstack, *src1);
+
+		src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+
+		if (STACK_REG_P (*dest))
+		  replace_reg (dest, FIRST_STACK_REG);
+
+		if (src1_note)
+		  {
+		    replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+		    regstack->top--;
+		    CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1));
+		  }
+
+		replace_reg (src1, FIRST_STACK_REG);
+		break;
+
 	      case UNSPEC_SIN:
 	      case UNSPEC_COS:
 	      case UNSPEC_FRNDINT:
-- 
GitLab