toplev.c (rest_of_compilation): Fix register_life_up_to_date handling...
authorJan Hubicka <jh@suse.cz>
Sun, 15 Jul 2001 16:59:06 +0000 (18:59 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sun, 15 Jul 2001 16:59:06 +0000 (16:59 +0000)
* toplev.c (rest_of_compilation): Fix register_life_up_to_date
handling; move unconditional splitting before mode switching.

* i386.md (type): Add fistp type.
(i387, length_attr, scheduling definitions): Handle this type.
(fix_trunc?f?i2): Revamp to use mode switching.
(fix_trunct?f?i_nonmemory, fix_trunc?f?i_memory): New patterns.
* i386.h (fp_cw_mode): New enum
(OPTIMIZE_MODE_SWITCHING, NUM_MODES_FOR_MODE_SWITCHING, MODE_NEEDED,
MODE_PRIORITY_TO_MODE, ENUM_MODE_SET): New macros.

From-SVN: r44027

gcc/ChangeLog
gcc/config/i386/i386.h
gcc/config/i386/i386.md
gcc/toplev.c

index 0246e85aa20feedaa2ff1342cb125127e8865262..b39e15e67be1bc0ab739bd15fcb7e15cd58a9e4c 100644 (file)
@@ -1,3 +1,16 @@
+Sun Jul 15 14:07:36 CEST 2001  Jan Hubicka  <jh@suse.cz>
+
+       * toplev.c (rest_of_compilation): Fix register_life_up_to_date
+       handling; move unconditional splitting before mode switching.
+
+       * i386.md (type): Add fistp type.
+       (i387, length_attr, scheduling definitions): Handle this type.
+       (fix_trunc?f?i2): Revamp to use mode switching.
+       (fix_trunct?f?i_nonmemory, fix_trunc?f?i_memory): New patterns.
+       * i386.h (fp_cw_mode): New enum
+       (OPTIMIZE_MODE_SWITCHING, NUM_MODES_FOR_MODE_SWITCHING, MODE_NEEDED,
+       MODE_PRIORITY_TO_MODE, ENUM_MODE_SET): New macros.
+
 Sun Jul 15 12:53:51 2001  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
 
        * Makefile.in (integrate.o): Add debug.h.
index 5869602ef51e56fcc400d1ba2b0aa6eb556e35c6..408ea2bac120dddb4782a392b13406b703c91b60 100644 (file)
@@ -3117,6 +3117,69 @@ extern const char * const qi_high_reg_name[];    /* names for 8 bit regs (high) */
 extern enum reg_class const regclass_map[];    /* smalled class containing REGNO */
 extern struct rtx_def *ix86_compare_op0;       /* operand 0 for comparisons */
 extern struct rtx_def *ix86_compare_op1;       /* operand 1 for comparisons */
+\f
+/* To properly truncate FP values into integers, we need to set i387 control
+   word.  We can't emit proper mode switching code before reload, as spills
+   generated by reload may truncate values incorrectly, but we still can avoid
+   redundant computation of new control word by the mode switching pass.
+   The fldcw instructions are still emitted redundantly, but this is probably
+   not going to be noticeable problem, as most CPUs do have fast path for
+   the sequence.  
+
+   The machinery is to emit simple truncation instructions and split them
+   before reload to instructions having USEs of two memory locations that
+   are filled by this code to old and new control word.
+   Post-reload pass may be later used to eliminate the redundant fildcw if
+   needed.  */
+
+enum fp_cw_mode {FP_CW_STORED, FP_CW_UNINITIALIZED, FP_CW_ANY};
+
+/* Define this macro if the port needs extra instructions inserted
+   for mode switching in an optimizing compilation.  */
+
+#define OPTIMIZE_MODE_SWITCHING(ENTITY) 1
+
+/* If you define `OPTIMIZE_MODE_SWITCHING', you have to define this as
+   initializer for an array of integers.  Each initializer element N
+   refers to an entity that needs mode switching, and specifies the
+   number of different modes that might need to be set for this
+   entity.  The position of the initializer in the initializer -
+   starting counting at zero - determines the integer that is used to
+   refer to the mode-switched entity in question.  */
+
+#define NUM_MODES_FOR_MODE_SWITCHING { FP_CW_ANY }
+
+/* ENTITY is an integer specifying a mode-switched entity.  If
+   `OPTIMIZE_MODE_SWITCHING' is defined, you must define this macro to
+   return an integer value not larger than the corresponding element
+   in `NUM_MODES_FOR_MODE_SWITCHING', to denote the mode that ENTITY
+   must be switched into prior to the execution of INSN.  */
+
+#define MODE_NEEDED(ENTITY, I)                                         \
+  (GET_CODE (I) == CALL_INSN                                           \
+   || (GET_CODE (I) == INSN && (asm_noperands (PATTERN (I)) >= 0       \
+                               || GET_CODE (PATTERN (I)) == ASM_INPUT))\
+   ? FP_CW_UNINITIALIZED                                               \
+   : recog_memoized (I) < 0 || get_attr_type (I) != TYPE_FISTP         \
+   ? FP_CW_ANY                                                         \
+   : FP_CW_STORED)
+
+/* This macro specifies the order in which modes for ENTITY are
+   processed.  0 is the highest priority.  */
+
+#define MODE_PRIORITY_TO_MODE(ENTITY, N) N
+
+/* Generate one or more insns to set ENTITY to MODE.  HARD_REG_LIVE
+   is the set of hard registers live at the point where the insn(s)
+   are to be inserted.  */
+
+#define EMIT_MODE_SET(ENTITY, MODE, HARD_REGS_LIVE)                    \
+  (MODE == FP_CW_STORED                                                        \
+   ? emit_i387_cw_initialization (assign_386_stack_local (HImode, 1),  \
+                                 assign_386_stack_local (HImode, 2)), 0\
+   : 0)
+
 \f
 /*
 Local variables:
index baff6bc7745314491253fd89adc77f75271dd677..56158b9b22eab3b84b6de0b5067d1c469f2d185a 100644 (file)
 ;; A basic instruction type.  Refinements due to arguments to be
 ;; provided in other attributes.
 (define_attr "type"
-  "other,multi,alu1,negnot,alu,icmp,test,imov,imovx,lea,incdec,ishift,imul,idiv,ibr,setcc,push,pop,call,callv,icmov,fmov,fop,fop1,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,str,cld,sse,mmx"
+  "other,multi,alu1,negnot,alu,icmp,test,imov,imovx,lea,incdec,ishift,imul,idiv,ibr,setcc,push,pop,call,callv,icmov,fmov,fop,fop1,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,str,cld,sse,mmx,fistp"
   (const_string "other"))
 
 ;; Main data type used by the insn
 
 ;; Set for i387 operations.
 (define_attr "i387" ""
-  (if_then_else (eq_attr "type" "fmov,fop,fop1,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch")
+  (if_then_else (eq_attr "type" "fmov,fop,fop1,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,fistp")
     (const_int 1)
     (const_int 0)))
 
         (const_int 1)))
 
 ;; The (bounding maximum) length of an instruction in bytes.
+;; ??? fistp is in fact fldcw/fistp/fldcw sequence.  Later we may want
+;; to split it and compute proper length as for other insns.
 (define_attr "length" ""
-  (cond [(eq_attr "type" "other,multi")
+  (cond [(eq_attr "type" "other,multi,fistp")
           (const_int 16)
         ]
         (plus (plus (attr "modrm")
           (const_string "unknown")
         (eq_attr "type" "lea,fcmov,fpspc,cld")
           (const_string "none")
+        (eq_attr "type" "fistp")
+          (const_string "both")
         (eq_attr "type" "push")
           (if_then_else (match_operand 1 "memory_operand" "")
             (const_string "both")
 ; integer instructions, because of the inpaired fxch instruction.
 (define_function_unit "pent_np" 1 0
   (and (eq_attr "cpu" "pentium")
-       (eq_attr "type" "fmov,fop,fop1,fsgn,fmul,fpspc,fcmov,fcmp"))
+       (eq_attr "type" "fmov,fop,fop1,fsgn,fmul,fpspc,fcmov,fcmp,fistp"))
   2 2
-  [(eq_attr "type" "!fmov,fop,fop1,fsgn,fmul,fpspc,fcmov,fcmp")])
+  [(eq_attr "type" "!fmov,fop,fop1,fsgn,fmul,fpspc,fcmov,fcmp,fistp")])
 
 (define_function_unit "fpu" 1 0
   (and (eq_attr "cpu" "pentium")
 ; ??? Trivial fp operations such as fabs or fchs takes only one cycle.
 (define_function_unit "fpu" 1 0
   (and (eq_attr "cpu" "pentium")
-       (eq_attr "type" "fop,fop1"))
+       (eq_attr "type" "fop,fop1,fistp"))
   3 1)
 
 ; Multiplication takes 3 cycles and is only half pipelined.
 
 (define_function_unit "ppro_p0" 1 0
   (and (eq_attr "cpu" "pentiumpro")
-       (eq_attr "type" "fop,fop1,fsgn"))
+       (eq_attr "type" "fop,fop1,fsgn,fistp"))
   3 1)
 
 (define_function_unit "ppro_p0" 1 0
 
 (define_function_unit "fpu" 1 0
   (and (eq_attr "cpu" "pentiumpro")
-       (eq_attr "type" "fop,fop1,fsgn,fmov,fcmp,fcmov"))
+       (eq_attr "type" "fop,fop1,fsgn,fmov,fcmp,fcmov,fistp"))
   1 1)
 
 (define_function_unit "fpu" 1 0
 
 (define_function_unit "k6_fpu" 1 1
   (and (eq_attr "cpu" "k6")
-       (eq_attr "type" "fop,fop1,fmov,fcmp"))
+       (eq_attr "type" "fop,fop1,fmov,fcmp,fistp"))
   2 2)
 
 (define_function_unit "k6_fpu" 1 1
   42 42)
 
 (define_attr "athlon_fpunits" "none,store,mul,add,muladd,any"
-  (cond [(eq_attr "type" "fop,fop1,fcmp")
+  (cond [(eq_attr "type" "fop,fop1,fcmp,fistp")
           (const_string "add")
          (eq_attr "type" "fmul,fdiv,fpspc,fsgn,fcmov")
           (const_string "mul")
 
 (define_function_unit "athlon_fp" 3 0
   (and (eq_attr "cpu" "athlon")
-       (eq_attr "type" "fop,fop1,fmul"))
+       (eq_attr "type" "fop,fop1,fmul,fistp"))
   4 1)
 
 ;; XFmode loads are slow.
 ;; Signed conversion to DImode.
 
 (define_expand "fix_truncxfdi2"
-  [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
-                  (fix:DI (match_operand:XF 1 "register_operand" "")))
-             (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))
-             (clobber (match_scratch:XF 5 ""))])]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "")
+        (fix:DI (match_operand:XF 1 "register_operand" "")))]
   "TARGET_80387 && !TARGET_64BIT"
-  "operands[2] = assign_386_stack_local (HImode, 1);
-   operands[3] = assign_386_stack_local (HImode, 2);
-   emit_i387_cw_initialization (operands[2], operands[3]);
-   operands[4] = assign_386_stack_local (DImode, 0);")
+  "")
 
 (define_expand "fix_trunctfdi2"
-  [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
-                  (fix:DI (match_operand:TF 1 "register_operand" "")))
-             (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))
-             (clobber (match_scratch:XF 5 ""))])]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "")
+       (fix:DI (match_operand:TF 1 "register_operand" "")))]
   "TARGET_80387"
-  "operands[2] = assign_386_stack_local (HImode, 1);
-   operands[3] = assign_386_stack_local (HImode, 2);
-   emit_i387_cw_initialization (operands[2], operands[3]);
-   operands[4] = assign_386_stack_local (DImode, 0);")
+  "")
 
 (define_expand "fix_truncdfdi2"
-  [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
-                  (fix:DI (match_operand:DF 1 "register_operand" "")))
-             (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))
-             (clobber (match_scratch:XF 5 ""))])]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "")
+        (fix:DI (match_operand:DF 1 "register_operand" "")))]
   "TARGET_80387 || (TARGET_SSE2 && TARGET_64BIT)"
 {
   if (TARGET_SSE2 && TARGET_64BIT)
        emit_move_insn (operands[0], out);
      DONE;
    }
-  else
-   {
-     operands[2] = assign_386_stack_local (HImode, 1);
-     operands[3] = assign_386_stack_local (HImode, 2);
-     emit_i387_cw_initialization (operands[2], operands[3]);
-     operands[4] = assign_386_stack_local (DImode, 0);
-   }
 })
 
 (define_expand "fix_truncsfdi2"
-  [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
-                  (fix:DI (match_operand:SF 1 "register_operand" "")))
-             (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))
-             (clobber (match_scratch:XF 5 ""))])]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "")
+       (fix:DI (match_operand:SF 1 "register_operand" "")))]
   "TARGET_80387 || (TARGET_SSE && TARGET_64BIT)"
 {
-  if (TARGET_SSE2 && TARGET_64BIT)
+  if (TARGET_SSE && TARGET_64BIT)
    {
      rtx out = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (DImode);
      emit_insn (gen_fix_truncsfdi_sse (out, operands[1]));
        emit_move_insn (operands[0], out);
      DONE;
    }
-  else
-   {
-     operands[2] = assign_386_stack_local (HImode, 1);
-     operands[3] = assign_386_stack_local (HImode, 2);
-     emit_i387_cw_initialization (operands[2], operands[3]);
-     operands[4] = assign_386_stack_local (DImode, 0);
-   }
 })
 
-(define_insn "*fix_truncdi_1"
+;; See the comments in i386.h near OPTIMIZE_MODE_SWITCHING for the description
+;; of the machinery.
+(define_insn_and_split "*fix_truncdi_1"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r")
+       (fix:DI (match_operand 1 "register_operand" "f,f")))]
+  "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))
+   && !reload_completed && !reload_in_progress
+   && (!SSE_FLOAT_MODE_P (GET_MODE (operands[1])) || !TARGET_64BIT)"
+  "#"
+  ""
+  [(const_int 0)]
+{
+  operands[2] = assign_386_stack_local (HImode, 1);
+  operands[3] = assign_386_stack_local (HImode, 2);
+  if (memory_operand (operands[0], VOIDmode))
+    emit_insn (gen_fix_truncdi_memory (operands[0], operands[1],
+                                      operands[2], operands[3]));
+  else
+    {
+      operands[4] = assign_386_stack_local (DImode, 0);
+      emit_insn (gen_fix_truncdi_nomemory (operands[0], operands[1],
+                                          operands[2], operands[3],
+                                          operands[4]));
+    }
+  DONE;
+}
+  [(set_attr "type" "fistp")])
+
+(define_insn "fix_truncdi_nomemory"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r")
        (fix:DI (match_operand 1 "register_operand" "f,f")))
    (use (match_operand:HI 2 "memory_operand" "m,m"))
    (use (match_operand:HI 3 "memory_operand" "m,m"))
    (clobber (match_operand:DI 4 "memory_operand" "=m,m"))
-   (clobber (match_scratch 5 "=&1f,&1f"))]
+   (clobber (match_scratch:DF 5 "=&1f,&1f"))]
   "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))
-   && (!TARGET_SSE2 || !TARGET_64BIT
-       || !SSE_FLOAT_MODE_P (GET_MODE (operands[1])))"
-  "* return output_fix_trunc (insn, operands);"
-  [(set_attr "type" "multi")])
+   && (!SSE_FLOAT_MODE_P (GET_MODE (operands[1])) || !TARGET_64BIT)"
+  "#"
+  [(set_attr "type" "fistp")])
+
+(define_insn "fix_truncdi_memory"
+  [(set (match_operand:DI 0 "memory_operand" "=m")
+       (fix:DI (match_operand 1 "register_operand" "f")))
+   (use (match_operand:HI 2 "memory_operand" "m"))
+   (use (match_operand:HI 3 "memory_operand" "m"))
+   (clobber (match_scratch:DF 4 "=&1f"))]
+  "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))
+   && (!SSE_FLOAT_MODE_P (GET_MODE (operands[1])) || !TARGET_64BIT)"
+  "* operands[5] = operands[4]; return output_fix_trunc (insn, operands);"
+  [(set_attr "type" "fistp")])
 
 (define_split 
   [(set (match_operand:DI 0 "register_operand" "")
   [(parallel [(set (match_dup 4) (fix:DI (match_dup 1)))
              (use (match_dup 2))
              (use (match_dup 3))
-             (clobber (match_dup 4))
              (clobber (match_dup 5))])
    (set (match_dup 0) (match_dup 4))]
   "")
 
+(define_split 
+  [(set (match_operand:DI 0 "memory_operand" "")
+       (fix:DI (match_operand 1 "register_operand" "")))
+   (use (match_operand:HI 2 "memory_operand" ""))
+   (use (match_operand:HI 3 "memory_operand" ""))
+   (clobber (match_operand:DI 4 "memory_operand" ""))
+   (clobber (match_scratch 5 ""))]
+  "reload_completed"
+  [(parallel [(set (match_dup 0) (fix:DI (match_dup 1)))
+             (use (match_dup 2))
+             (use (match_dup 3))
+             (clobber (match_dup 5))])]
+  "")
+
 ;; When SSE available, it is always faster to use it!
 (define_insn "fix_truncsfdi_sse"
   [(set (match_operand:DI 0 "register_operand" "=r")
 ;; Signed conversion to SImode.
 
 (define_expand "fix_truncxfsi2"
-  [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
-                  (fix:SI (match_operand:XF 1 "register_operand" "")))
-             (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))])]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "")
+       (fix:SI (match_operand:XF 1 "register_operand" "")))]
   "TARGET_80387 && !TARGET_64BIT"
-  "operands[2] = assign_386_stack_local (HImode, 1);
-   operands[3] = assign_386_stack_local (HImode, 2);
-   emit_i387_cw_initialization (operands[2], operands[3]);
-   operands[4] = assign_386_stack_local (SImode, 0);")
+  "")
 
 (define_expand "fix_trunctfsi2"
-  [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
-                  (fix:SI (match_operand:TF 1 "register_operand" "")))
-             (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))])]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "")
+       (fix:SI (match_operand:TF 1 "register_operand" "")))]
   "TARGET_80387"
-  "operands[2] = assign_386_stack_local (HImode, 1);
-   operands[3] = assign_386_stack_local (HImode, 2);
-   emit_i387_cw_initialization (operands[2], operands[3]);
-   operands[4] = assign_386_stack_local (SImode, 0);")
+  "")
 
 (define_expand "fix_truncdfsi2"
-  [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
-                  (fix:SI (match_operand:DF 1 "register_operand" "")))
-             (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))])]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "")
+       (fix:SI (match_operand:DF 1 "register_operand" "")))]
   "TARGET_80387 || TARGET_SSE2"
 {
   if (TARGET_SSE2)
        emit_move_insn (operands[0], out);
      DONE;
    }
-  else
-   {
-     operands[2] = assign_386_stack_local (HImode, 1);
-     operands[3] = assign_386_stack_local (HImode, 2);
-     emit_i387_cw_initialization (operands[2], operands[3]);
-     operands[4] = assign_386_stack_local (SImode, 0);
-   }
 })
 
 (define_expand "fix_truncsfsi2"
-  [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
-                  (fix:SI (match_operand:SF 1 "register_operand" "")))
-             (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))])]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "")
+       (fix:SI (match_operand:SF 1 "register_operand" "")))]
   "TARGET_80387 || TARGET_SSE"
 {
-  if (TARGET_SSE2)
+  if (TARGET_SSE)
    {
      rtx out = REG_P (operands[0]) ? operands[0] : gen_reg_rtx (SImode);
      emit_insn (gen_fix_truncsfsi_sse (out, operands[1]));
        emit_move_insn (operands[0], out);
      DONE;
    }
-  else
-   {
-     operands[2] = assign_386_stack_local (HImode, 1);
-     operands[3] = assign_386_stack_local (HImode, 2);
-     emit_i387_cw_initialization (operands[2], operands[3]);
-     operands[4] = assign_386_stack_local (SImode, 0);
-   }
 })
 
-(define_insn "*fix_truncsi_1"
+;; See the comments in i386.h near OPTIMIZE_MODE_SWITCHING for the description
+;; of the machinery.
+(define_insn_and_split "*fix_truncsi_1"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?r")
+       (fix:SI (match_operand 1 "register_operand" "f,f")))]
+  "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))
+   && !reload_completed && !reload_in_progress
+   && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))"
+  "#"
+  ""
+  [(const_int 0)]
+{
+  operands[2] = assign_386_stack_local (HImode, 1);
+  operands[3] = assign_386_stack_local (HImode, 2);
+  if (memory_operand (operands[0], VOIDmode))
+    emit_insn (gen_fix_truncsi_memory (operands[0], operands[1],
+                                      operands[2], operands[3]));
+  else
+    {
+      operands[4] = assign_386_stack_local (SImode, 0);
+      emit_insn (gen_fix_truncsi_nomemory (operands[0], operands[1],
+                                          operands[2], operands[3],
+                                          operands[4]));
+    }
+  DONE;
+}
+  [(set_attr "type" "fistp")])
+
+(define_insn "fix_truncsi_nomemory"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?r")
        (fix:SI (match_operand 1 "register_operand" "f,f")))
    (use (match_operand:HI 2 "memory_operand" "m,m"))
    (use (match_operand:HI 3 "memory_operand" "m,m"))
    (clobber (match_operand:SI 4 "memory_operand" "=m,m"))]
   "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))
-   && (!TARGET_SSE2 || !SSE_FLOAT_MODE_P (GET_MODE (operands[1])))"
+   && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))"
+  "#"
+  [(set_attr "type" "fistp")])
+
+(define_insn "fix_truncsi_memory"
+  [(set (match_operand:SI 0 "memory_operand" "=m")
+       (fix:SI (match_operand 1 "register_operand" "f")))
+   (use (match_operand:HI 2 "memory_operand" "m"))
+   (use (match_operand:HI 3 "memory_operand" "m"))]
+  "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))
+   && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))"
   "* return output_fix_trunc (insn, operands);"
-  [(set_attr "type" "multi")])
+  [(set_attr "type" "fistp")])
 
 ;; When SSE available, it is always faster to use it!
 (define_insn "fix_truncsfsi_sse"
   "reload_completed"
   [(parallel [(set (match_dup 4) (fix:SI (match_dup 1)))
              (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))])
+             (use (match_dup 3))])
    (set (match_dup 0) (match_dup 4))]
   "")
 
+(define_split 
+  [(set (match_operand:SI 0 "memory_operand" "")
+       (fix:SI (match_operand 1 "register_operand" "")))
+   (use (match_operand:HI 2 "memory_operand" ""))
+   (use (match_operand:HI 3 "memory_operand" ""))
+   (clobber (match_operand:SI 4 "memory_operand" ""))]
+  "reload_completed"
+  [(parallel [(set (match_dup 0) (fix:SI (match_dup 1)))
+             (use (match_dup 2))
+             (use (match_dup 3))])]
+  "")
+
 ;; Signed conversion to HImode.
 
 (define_expand "fix_truncxfhi2"
-  [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
-                  (fix:HI (match_operand:XF 1 "register_operand" "")))
-             (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))])]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "")
+        (fix:HI (match_operand:XF 1 "register_operand" "")))]
   "TARGET_80387 && !TARGET_64BIT"
-  "operands[2] = assign_386_stack_local (HImode, 1);
-   operands[3] = assign_386_stack_local (HImode, 2);
-   emit_i387_cw_initialization (operands[2], operands[3]);
-   operands[4] = assign_386_stack_local (HImode, 0);")
+  "")
 
 (define_expand "fix_trunctfhi2"
-  [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
-                  (fix:HI (match_operand:TF 1 "register_operand" "")))
-             (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))])]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "")
+       (fix:HI (match_operand:TF 1 "register_operand" "")))]
   "TARGET_80387"
-  "operands[2] = assign_386_stack_local (HImode, 1);
-   operands[3] = assign_386_stack_local (HImode, 2);
-   emit_i387_cw_initialization (operands[2], operands[3]);
-   operands[4] = assign_386_stack_local (HImode, 0);")
+  "")
 
 (define_expand "fix_truncdfhi2"
-  [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
-                  (fix:HI (match_operand:DF 1 "register_operand" "")))
-             (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))])]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "")
+       (fix:HI (match_operand:DF 1 "register_operand" "")))]
   "TARGET_80387 && !TARGET_SSE2"
-  "operands[2] = assign_386_stack_local (HImode, 1);
-   operands[3] = assign_386_stack_local (HImode, 2);
-   emit_i387_cw_initialization (operands[2], operands[3]);
-   operands[4] = assign_386_stack_local (HImode, 0);")
+  "")
 
 (define_expand "fix_truncsfhi2"
-  [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
-                  (fix:HI (match_operand:SF 1 "register_operand" "")))
-             (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))])]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "")
+       (fix:HI (match_operand:SF 1 "register_operand" "")))]
   "TARGET_80387 && !TARGET_SSE"
-  "operands[2] = assign_386_stack_local (HImode, 1);
-   operands[3] = assign_386_stack_local (HImode, 2);
-   emit_i387_cw_initialization (operands[2], operands[3]);
-   operands[4] = assign_386_stack_local (HImode, 0);")
+  "")
 
-(define_insn "*fix_trunchi_1"
+;; See the comments in i386.h near OPTIMIZE_MODE_SWITCHING for the description
+;; of the machinery.
+(define_insn_and_split "*fix_trunchi_1"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=m,?r")
+       (fix:HI (match_operand 1 "register_operand" "f,f")))]
+  "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))
+   && !reload_completed && !reload_in_progress
+   && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))"
+  "#"
+  ""
+  [(const_int 0)]
+{
+  operands[2] = assign_386_stack_local (HImode, 1);
+  operands[3] = assign_386_stack_local (HImode, 2);
+  if (memory_operand (operands[0], VOIDmode))
+    emit_insn (gen_fix_trunchi_memory (operands[0], operands[1],
+                                      operands[2], operands[3]));
+  else
+    {
+      operands[4] = assign_386_stack_local (HImode, 0);
+      emit_insn (gen_fix_trunchi_nomemory (operands[0], operands[1],
+                                          operands[2], operands[3],
+                                          operands[4]));
+    }
+  DONE;
+}
+  [(set_attr "type" "fistp")])
+
+(define_insn "fix_trunchi_nomemory"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=m,?r")
        (fix:HI (match_operand 1 "register_operand" "f,f")))
    (use (match_operand:HI 2 "memory_operand" "m,m"))
    (use (match_operand:HI 3 "memory_operand" "m,m"))
    (clobber (match_operand:HI 4 "memory_operand" "=m,m"))]
   "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))
-   && (TARGET_SSE2 || !SSE_FLOAT_MODE_P (GET_MODE (operands[1])))"
+   && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))"
+  "#"
+  [(set_attr "type" "fistp")])
+
+(define_insn "fix_trunchi_memory"
+  [(set (match_operand:HI 0 "memory_operand" "=m")
+       (fix:HI (match_operand 1 "register_operand" "f")))
+   (use (match_operand:HI 2 "memory_operand" "m"))
+   (use (match_operand:HI 3 "memory_operand" "m"))]
+  "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))
+   && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))"
   "* return output_fix_trunc (insn, operands);"
-  [(set_attr "type" "multi")])
+  [(set_attr "type" "fistp")])
+
+(define_split 
+  [(set (match_operand:HI 0 "memory_operand" "")
+       (fix:HI (match_operand 1 "register_operand" "")))
+   (use (match_operand:HI 2 "memory_operand" ""))
+   (use (match_operand:HI 3 "memory_operand" ""))
+   (clobber (match_operand:HI 4 "memory_operand" ""))]
+  "reload_completed"
+  [(parallel [(set (match_dup 0) (fix:HI (match_dup 1)))
+             (use (match_dup 2))
+             (use (match_dup 3))])]
+  "")
 
 (define_split 
   [(set (match_operand:HI 0 "register_operand" "")
index b3154dcdaec7703179b676fb09a1367bb078a44d..746ea908afa368888fd3d371716afaa15c789c30 100644 (file)
@@ -3327,7 +3327,6 @@ rest_of_compilation (decl)
   life_analysis (insns, rtl_dump_file, PROP_FINAL);
   timevar_pop (TV_FLOW);
 
-  register_life_up_to_date = 1;
   no_new_pseudos = 1;
 
   if (warn_uninitialized || extra_warnings)
@@ -3415,15 +3414,18 @@ rest_of_compilation (decl)
       ggc_collect ();
     }
 
+  /* Do unconditional splitting before register allocation to allow machine
+     description to add extra information not needed previously.  */
+  split_all_insns (1);
+
   /* Any of the several passes since flow1 will have munged register
      lifetime data a bit.  */
-  if (optimize > 0)
-    register_life_up_to_date = 0;
+  register_life_up_to_date = 0;
 
 #ifdef OPTIMIZE_MODE_SWITCHING
   timevar_push (TV_GCSE);
 
-  no_new_pseudos = 1;
+  no_new_pseudos = 0;
   if (optimize_mode_switching (NULL))
     {
       /* We did work, and so had to regenerate global life information.
@@ -3431,15 +3433,13 @@ rest_of_compilation (decl)
         information below.  */
       register_life_up_to_date = 1;
     }
-  no_new_pseudos = 0;
+  no_new_pseudos = 1;
 
   timevar_pop (TV_GCSE);
 #endif
 
   timevar_push (TV_SCHED);
 
-  split_all_insns (1);
-
 #ifdef INSN_SCHEDULING
 
   /* Print function header into sched dump now