OSDN Git Service

* i386.c (ix86_split_to_parts): Return number of part required;
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 2 Jan 2001 19:24:27 +0000 (19:24 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 2 Jan 2001 19:24:27 +0000 (19:24 +0000)
handle TFmodes.
(print_operand, ix86_expand_branch, ix86_expand_fp_movcc): Handle
TFmodes.
(ix86_split_long_move): Use number of part returned
by ix86_split_to_parts
* i386.h (MASK_128BIT_LONG_DOUBLE, TARGET_128BIT_LONG_DOUBLE):
New macros.
(TARGET_SWITCHES): Add 128bit-long-double and 96bit-long-double
(LONG_DOUBLE_TYPE_SIZE): Change from constant.
(MAX_LONG_DOUBLE_TYPE_SIZE): New macro.
(INTEL_EXTENDED_IEEE_FORMAT): Likewise.
(ALIGN_MODE_128): Add TFmode.
(IS_STACK_MODE): Likewise.
(HARD_REGNO_NREGS): TFmode needs 3 registers.
(HARD_REGNO_OK): Support TFmodes.
(ASM_OUTPUT_LONG_DOUBLE): Handle TFmodes.
* i386.md (scheduler definitions): Use memory operand to determine
fst/fld instructions; use mode attribute to determine real mode of
the instruction.
(*tf): New patterns, expanders and splitters; based on XFmode patterns.
* invoke.texi (128bit-long-double, 96bit-long-double): Document.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@38633 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/i386.md
gcc/invoke.texi

index 884a4be..f64a007 100644 (file)
@@ -1,3 +1,28 @@
+Tue Jan  2 20:21:31 MET 2001  Jan Hubicka  <jh@suse.cz>
+
+       * i386.c (ix86_split_to_parts): Return number of part required;
+       handle TFmodes.
+       (print_operand, ix86_expand_branch, ix86_expand_fp_movcc): Handle
+       TFmodes.
+       (ix86_split_long_move): Use number of part returned
+       by ix86_split_to_parts
+       * i386.h (MASK_128BIT_LONG_DOUBLE, TARGET_128BIT_LONG_DOUBLE):
+       New macros.
+       (TARGET_SWITCHES): Add 128bit-long-double and 96bit-long-double
+       (LONG_DOUBLE_TYPE_SIZE): Change from constant.
+       (MAX_LONG_DOUBLE_TYPE_SIZE): New macro.
+       (INTEL_EXTENDED_IEEE_FORMAT): Likewise.
+       (ALIGN_MODE_128): Add TFmode.
+       (IS_STACK_MODE): Likewise.
+       (HARD_REGNO_NREGS): TFmode needs 3 registers.
+       (HARD_REGNO_OK): Support TFmodes.
+       (ASM_OUTPUT_LONG_DOUBLE): Handle TFmodes.
+       * i386.md (scheduler definitions): Use memory operand to determine
+       fst/fld instructions; use mode attribute to determine real mode of
+       the instruction.
+       (*tf): New patterns, expanders and splitters; based on XFmode patterns.
+       * invoke.texi (128bit-long-double, 96bit-long-double): Document.
+
 2001-01-02  Mark Mitchell  <mark@codesourcery.com>
 
        * tree.def (TRUTH_NOT_EXPR): Improve documentation.
index 3bd1b81..c8a25c4 100644 (file)
@@ -404,7 +404,7 @@ static rtx * ix86_pent_find_pair PARAMS ((rtx *, rtx *, enum attr_pent_pair,
                                         rtx));
 static void ix86_init_machine_status PARAMS ((struct function *));
 static void ix86_mark_machine_status PARAMS ((struct function *));
-static void ix86_split_to_parts PARAMS ((rtx, rtx *, enum machine_mode));
+static int ix86_split_to_parts PARAMS ((rtx, rtx *, enum machine_mode));
 static int ix86_safe_length_prefix PARAMS ((rtx));
 static HOST_WIDE_INT ix86_compute_frame_size PARAMS((HOST_WIDE_INT,
                                                     int *, int *, int *));
@@ -3337,6 +3337,7 @@ print_operand (file, x, code)
              return;
 
            case 12:
+           case 16:
              putc ('t', file);
              return;
 
@@ -3466,7 +3467,8 @@ print_operand (file, x, code)
       fprintf (file, "%s", dstr);
     }
 
-  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == XFmode)
+  else if (GET_CODE (x) == CONST_DOUBLE
+          && (GET_MODE (x) == XFmode || GET_MODE (x) == TFmode))
     {
       REAL_VALUE_TYPE r;
       char dstr[30];
@@ -4769,6 +4771,7 @@ ix86_prepare_fp_compare_args (code, pop0, pop1)
 
   if (fpcmp_mode == CCFPUmode
       || op_mode == XFmode
+      || op_mode == TFmode
       || ix86_use_fcomi_compare (code))
     {
       op0 = force_reg (op_mode, op0);
@@ -5048,6 +5051,7 @@ ix86_expand_branch (code, label)
     case SFmode:
     case DFmode:
     case XFmode:
+    case TFmode:
       /* Don't expand the comparison early, so that we get better code
         when jump or whoever decides to reverse the comparison.  */
       {
@@ -5633,13 +5637,13 @@ ix86_expand_fp_movcc (operands)
    For pushes, it returns just stack offsets; the values will be saved
    in the right order.  Maximally three parts are generated.  */
 
-static void
+static int
 ix86_split_to_parts (operand, parts, mode)
      rtx operand;
      rtx *parts;
      enum machine_mode mode;
 {
-  int size = GET_MODE_SIZE (mode) / 4;
+  int size = mode == TFmode ? 3 : GET_MODE_SIZE (mode) / 4;
 
   if (GET_CODE (operand) == REG && MMX_REGNO_P (REGNO (operand)))
     abort ();
@@ -5689,12 +5693,13 @@ ix86_split_to_parts (operand, parts, mode)
          else if (GET_CODE (operand) == CONST_DOUBLE)
            {
              REAL_VALUE_TYPE r;
-             long l[3];
+             long l[4];
 
              REAL_VALUE_FROM_CONST_DOUBLE (r, operand);
              switch (mode)
                {
                case XFmode:
+               case TFmode:
                  REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
                  parts[2] = GEN_INT (l[2]);
                  break;
@@ -5712,7 +5717,7 @@ ix86_split_to_parts (operand, parts, mode)
        }
     }
 
-  return;
+  return size;
 }
 
 /* Emit insns to perform a move or push of DI, DF, and XF values.
@@ -5726,7 +5731,7 @@ ix86_split_long_move (operands1)
 {
   rtx part[2][3];
   rtx operands[2];
-  int size = GET_MODE_SIZE (GET_MODE (operands1[0])) / 4;
+  int size;
   int push = 0;
   int collisions = 0;
 
@@ -5734,9 +5739,6 @@ ix86_split_long_move (operands1)
   operands[0] = copy_rtx (operands1[0]);
   operands[1] = copy_rtx (operands1[1]);
 
-  if (size < 2 || size > 3)
-    abort ();
-
   /* The only non-offsettable memory we handle is push.  */
   if (push_operand (operands[0], VOIDmode))
     push = 1;
@@ -5744,7 +5746,7 @@ ix86_split_long_move (operands1)
           && ! offsettable_memref_p (operands[0]))
     abort ();
 
-  ix86_split_to_parts (operands[0], part[0], GET_MODE (operands1[0]));
+  size = ix86_split_to_parts (operands[0], part[0], GET_MODE (operands1[0]));
   ix86_split_to_parts (operands[1], part[1], GET_MODE (operands1[0]));
 
   /* When emitting push, take care for source operands on the stack.  */
@@ -5794,7 +5796,15 @@ ix86_split_long_move (operands1)
   if (push)
     {
       if (size == 3)
-       emit_insn (gen_push (part[1][2]));
+       {
+         /* We use only first 12 bytes of TFmode value, but for pushing we
+            are required to adjust stack as if we were pushing real 16byte
+            value.  */
+         if (GET_MODE (operands1[0]) == TFmode)
+           emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+                                  GEN_INT (-4)));
+         emit_insn (gen_push (part[1][2]));
+       }
       emit_insn (gen_push (part[1][1]));
       emit_insn (gen_push (part[1][0]));
       return 1;
index 4f59fb8..8f219cf 100644 (file)
@@ -104,6 +104,7 @@ extern int target_flags;
 #define MASK_ACCUMULATE_OUTGOING_ARGS 0x00008000/* Accumulate outgoing args */
 #define MASK_MMX               0x00010000      /* Support MMX regs/builtins */
 #define MASK_SSE               0x00020000      /* Support SSE regs/builtins */
+#define MASK_128BIT_LONG_DOUBLE 0x00040000     /* long double size is 128bit */
 
 /* Temporary codegen switches */
 #define MASK_INTEL_SYNTAX      0x00000200
@@ -144,6 +145,11 @@ extern int target_flags;
    the 387 to be used, which is compatible with most calling conventions. */
 #define TARGET_FLOAT_RETURNS_IN_80387 (target_flags & MASK_FLOAT_RETURNS)
 
+/* Long double is 128bit instead of 96bit, even when only 80bits are used.
+   This mode wastes cache, but avoid missaligned data accesses and simplifies
+   address calculations.  */
+#define TARGET_128BIT_LONG_DOUBLE (target_flags & MASK_128BIT_LONG_DOUBLE)
+
 /* Disable generation of FP sin, cos and sqrt operations for 387.
    This is because FreeBSD lacks these in the math-emulator-code */
 #define TARGET_NO_FANCY_MATH_387 (target_flags & MASK_NO_FANCY_MATH_387)
@@ -295,6 +301,10 @@ extern const int x86_partial_reg_dependency, x86_memory_mismatch_stall;
     N_("Support MMX and SSE builtins") },                                    \
   { "no-sse",                  -MASK_SSE,                                    \
     N_("Do not support MMX and SSE builtins") },                             \
+  { "128bit-long-double",       MASK_128BIT_LONG_DOUBLE,                     \
+    N_("sizeof(long double) is 16.") },                                              \
+  { "96bit-long-double",       -MASK_128BIT_LONG_DOUBLE,                     \
+    N_("sizeof(long double) is 12.") },                                              \
   SUBTARGET_SWITCHES                                                         \
   { "", TARGET_DEFAULT, 0 }}
 
@@ -446,9 +456,18 @@ extern int ix86_arch;
 \f
 /* target machine storage layout */
 
-/* Define for XFmode extended real floating point support.
-   This will automatically cause REAL_ARITHMETIC to be defined.  */
-#define LONG_DOUBLE_TYPE_SIZE 96
+/* Define for XFmode or TFmode extended real floating point support.
+   This will automatically cause REAL_ARITHMETIC to be defined.
+   The XFmode is specified by i386 ABI, while TFmode may be faster
+   due to alignment and simplifications in the address calculations.
+ */
+#define LONG_DOUBLE_TYPE_SIZE (TARGET_128BIT_LONG_DOUBLE ? 128 : 96)
+#define MAX_LONG_DOUBLE_TYPE_SIZE 128
+/* Tell real.c that this is the 80-bit Intel extended float format
+   packaged in a 128-bit or 96bit entity.  */
+#define INTEL_EXTENDED_IEEE_FORMAT
+
 
 /* Define if you don't want extended real, but do want to use the
    software floating point emulator for REAL_ARITHMETIC and
@@ -515,8 +534,8 @@ extern int ix86_arch;
 
 /* Decide whether a variable of mode MODE must be 128 bit aligned.  */
 #define ALIGN_MODE_128(MODE) \
- ((MODE) == XFmode || ((MODE) == TImode) || (MODE) == V4SFmode \
-  || (MODE) == V4SImode)
+ ((MODE) == XFmode || (MODE) == TFmode || ((MODE) == TImode) \
+  || (MODE) == V4SFmode        || (MODE) == V4SImode)
 
 /* The published ABIs say that doubles should be aligned on word
    boundaries, so lower the aligment for structure fields unless
@@ -596,7 +615,8 @@ extern int ix86_arch;
    for details. */
 
 #define STACK_REGS
-#define IS_STACK_MODE(mode) (mode==DFmode || mode==SFmode || mode==XFmode)
+#define IS_STACK_MODE(mode) (mode==DFmode || mode==SFmode \
+                            || mode==XFmode || mode==TFmode)
 
 /* Number of actual hardware registers.
    The hardware registers are assigned numbers for the compiler
@@ -740,7 +760,9 @@ extern int ix86_arch;
 
 #define HARD_REGNO_NREGS(REGNO, MODE)   \
   (FP_REGNO_P (REGNO) || SSE_REGNO_P (REGNO) || MMX_REGNO_P (REGNO) ? 1 \
-   : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+   : (MODE == TFmode                                                   \
+      ? 3                                                              \
+      : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)))
 
 #define VALID_SSE_REG_MODE(MODE) \
     ((MODE) == TImode || (MODE) == V4SFmode || (MODE) == V4SImode)
@@ -765,7 +787,7 @@ extern int ix86_arch;
    : FP_REGNO_P (REGNO)                                                \
    ? ((GET_MODE_CLASS (MODE) == MODE_FLOAT                     \
        || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT)         \
-      && GET_MODE_UNIT_SIZE (MODE) <= (LONG_DOUBLE_TYPE_SIZE == 96 ? 12 : 8))\
+      && GET_MODE_UNIT_SIZE (MODE) <= 16)\
    : SSE_REGNO_P (REGNO) ? VALID_SSE_REG_MODE (MODE)           \
    : MMX_REGNO_P (REGNO) ? VALID_MMX_REG_MODE (MODE)           \
    /* Only SSE and MMX regs can hold vector modes.  */         \
@@ -2610,9 +2632,12 @@ do { long l[2];                                                          \
 
 #undef ASM_OUTPUT_LONG_DOUBLE
 #define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE)             \
-do { long l[3];                                                \
+do { long l[4];                                                \
      REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l);      \
-     fprintf (FILE, "%s\t0x%lx,0x%lx,0x%lx\n", ASM_LONG, l[0], l[1], l[2]); \
+     if (TARGET_128BIT_LONG_DOUBLE)                    \
+       fprintf (FILE, "%s\t0x%lx,0x%lx,0x%lx,0x0\n", ASM_LONG, l[0], l[1], l[2]); \
+     else \
+       fprintf (FILE, "%s\t0x%lx,0x%lx,0x%lx\n", ASM_LONG, l[0], l[1], l[2]); \
    } while (0)
 
 /* This is how to output an assembler line defining a `float' constant.  */
index 72954bf..836edc5 100644 (file)
 (define_function_unit "fpu" 1 0
   (and (eq_attr "cpu" "pentium")
        (and (eq_attr "type" "fmov")
-           (ior (and (eq_attr "memory" "store")
-                     (match_operand:XF 0 "memory_operand" ""))
-                (and (eq_attr "memory" "load")
-                     (match_operand:XF 1 "memory_operand" "")))))
+           (and (eq_attr "memory" "load,store")
+                (eq_attr "mode" "XF"))))
   3 3)
 
 (define_function_unit "pent_np" 1 0
   (and (eq_attr "cpu" "pentium")
        (and (eq_attr "type" "fmov")
-           (ior (and (eq_attr "memory" "store")
-                     (match_operand:XF 0 "memory_operand" ""))
-                (and (eq_attr "memory" "load")
-                     (match_operand:XF 1 "memory_operand" "")))))
+           (and (eq_attr "memory" "load,store")
+                (eq_attr "mode" "XF"))))
   3 3)
 
 (define_function_unit "fpu" 1 0
               (match_operand 1 "memory_operand" ""))
           (const_string "vector")
          (and (eq_attr "type" "fmov")
-              (ior (match_operand:XF 0 "memory_operand" "")
-                   (match_operand:XF 1 "memory_operand" "")))
+             (and (eq_attr "memory" "load,store")
+                  (eq_attr "mode" "XF")))
           (const_string "vector")]
        (const_string "direct")))
 
 (define_function_unit "athlon_fp" 3 0
   (and (eq_attr "cpu" "athlon")
        (and (eq_attr "type" "fmov")
-           (match_operand:XF 1 "memory_operand" "")))
+           (and (eq_attr "memory" "load")
+                (eq_attr "mode" "XF"))))
   10 1)
 
 (define_function_unit "athlon_fp" 3 0
   DONE;
 }")
 
+(define_expand "cmptf"
+  [(set (reg:CC 17)
+       (compare:CC (match_operand:TF 0 "cmp_fp_expander_operand" "")
+                   (match_operand:TF 1 "cmp_fp_expander_operand" "")))]
+  "TARGET_80387"
+  "
+{
+  ix86_compare_op0 = operands[0];
+  ix86_compare_op1 = operands[1];
+  DONE;
+}")
+
 (define_expand "cmpdf"
   [(set (reg:CC 17)
        (compare:CC (match_operand:DF 0 "cmp_fp_expander_operand" "")
   [(set_attr "type" "fcmp")
    (set_attr "mode" "XF")])
 
+(define_insn "*cmpfp_2_tf"
+  [(set (reg:CCFP 18)
+       (compare:CCFP
+         (match_operand:TF 0 "register_operand" "f")
+         (match_operand:TF 1 "register_operand" "f")))]
+  "TARGET_80387"
+  "* return output_fp_compare (insn, operands, 0, 0);"
+  [(set_attr "type" "fcmp")
+   (set_attr "mode" "XF")])
+
 (define_insn "*cmpfp_2_xf_1"
   [(set (match_operand:HI 0 "register_operand" "=a")
        (unspec:HI
   [(set_attr "type" "multi")
    (set_attr "mode" "XF")])
 
+(define_insn "*cmpfp_2_tf_1"
+  [(set (match_operand:HI 0 "register_operand" "=a")
+       (unspec:HI
+         [(compare:CCFP
+            (match_operand:TF 1 "register_operand" "f")
+            (match_operand:TF 2 "register_operand" "f"))] 9))]
+  "TARGET_80387"
+  "* return output_fp_compare (insn, operands, 2, 0);"
+  [(set_attr "type" "multi")
+   (set_attr "mode" "XF")])
+
 (define_insn "*cmpfp_2u"
   [(set (reg:CCFPU 18)
        (compare:CCFPU
   ""
   "ix86_expand_move (XFmode, operands); DONE;")
 
+(define_expand "movtf"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "")
+       (match_operand:TF 1 "general_operand" ""))]
+  ""
+  "ix86_expand_move (TFmode, operands); DONE;")
+
 ;; Size of pushdf is 3 (for sub) + 2 (for fstp) + memory operand size.
 ;; Size of pushdf using integer insturctions is 3+3*memory operand size
 ;; Pushing using integer instructions is longer except for constants
   [(set_attr "type" "multi")
    (set_attr "mode" "XF,SI,SI")])
 
+(define_insn "*pushtf_nointeger"
+  [(set (match_operand:TF 0 "push_operand" "=<,<,<")
+       (match_operand:TF 1 "general_no_elim_operand" "f,Fo,*r"))]
+  "optimize_size"
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+      /* %%% We loose REG_DEAD notes for controling pops if we split late.  */
+      operands[0] = gen_rtx_MEM (XFmode, stack_pointer_rtx);
+      operands[2] = stack_pointer_rtx;
+      operands[3] = GEN_INT (16);
+      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+       return \"sub{l}\\t{%3, %2|%2, %3}\;fstp%z0\\t%y0\";
+      else
+       return \"sub{l}\\t{%3, %2|%2, %3}\;fst%z0\\t%y0\";
+
+    case 1:
+    case 2:
+      return \"#\";
+
+    default:
+      abort ();
+    }
+}"
+  [(set_attr "type" "multi")
+   (set_attr "mode" "XF,SI,SI")])
+
 (define_insn "*pushxf_integer"
   [(set (match_operand:XF 0 "push_operand" "=<,<")
        (match_operand:XF 1 "general_no_elim_operand" "f#r,rFo#f"))]
   [(set_attr "type" "multi")
    (set_attr "mode" "XF,SI")])
 
+(define_insn "*pushtf_integer"
+  [(set (match_operand:TF 0 "push_operand" "=<,<")
+       (match_operand:TF 1 "general_no_elim_operand" "f#r,rFo#f"))]
+  "!optimize_size"
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+      /* %%% We loose REG_DEAD notes for controling pops if we split late.  */
+      operands[0] = gen_rtx_MEM (XFmode, stack_pointer_rtx);
+      operands[2] = stack_pointer_rtx;
+      operands[3] = GEN_INT (16);
+      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+       return \"sub{l}\\t{%3, %2|%2, %3}\;fstp%z0\\t%y0\";
+      else
+       return \"sub{l}\\t{%3, %2|%2, %3}\;fst%z0\\t%y0\";
+
+    case 1:
+      return \"#\";
+
+    default:
+      abort ();
+    }
+}"
+  [(set_attr "type" "multi")
+   (set_attr "mode" "XF,SI")])
+
 (define_split
-  [(set (match_operand:XF 0 "push_operand" "")
-       (match_operand:XF 1 "general_operand" ""))]
+  [(set (match_operand 0 "push_operand" "")
+       (match_operand 1 "general_operand" ""))]
   "reload_completed
+   && (GET_MODE (operands[0]) == XFmode
+       || GET_MODE (operands[0]) == TFmode
+       || GET_MODE (operands[0]) == DFmode)
    && (!REG_P (operands[1]) || !FP_REGNO_P (REGNO (operands[1])))"
   [(const_int 0)]
   "if (!ix86_split_long_move (operands)) abort (); DONE;")
   [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -12)))
    (set (mem:XF (reg:SI 7)) (match_dup 1))])
 
+(define_split
+  [(set (match_operand:TF 0 "push_operand" "")
+       (match_operand:TF 1 "register_operand" ""))]
+  "FP_REGNO_P (REGNO (operands[1]))"
+  [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -16)))
+   (set (mem:TF (reg:SI 7)) (match_dup 1))])
+
 ;; Do not use integer registers when optimizing for size
 (define_insn "*movxf_nointeger"
   [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,*r,o")
   [(set_attr "type" "fmov,fmov,fmov,multi,multi")
    (set_attr "mode" "XF,XF,XF,SI,SI")])
 
+(define_insn "*movtf_nointeger"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "=f,m,f,*r,o")
+       (match_operand:TF 1 "general_operand" "fm,f,G,*roF,F*r"))]
+  "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+   && optimize_size
+   && (reload_in_progress || reload_completed
+       || GET_CODE (operands[1]) != CONST_DOUBLE
+       || memory_operand (operands[0], TFmode))" 
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+      if (REG_P (operands[1])
+          && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+        return \"fstp\\t%y0\";
+      else if (STACK_TOP_P (operands[0]))
+        return \"fld%z1\\t%y1\";
+      else
+        return \"fst\\t%y0\";
+
+    case 1:
+      /* There is no non-popping store to memory for XFmode.  So if
+        we need one, follow the store with a load.  */
+      if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+        return \"fstp%z0\\t%y0\;fld%z0\\t%y0\";
+      else
+        return \"fstp%z0\\t%y0\";
+
+    case 2:
+      switch (standard_80387_constant_p (operands[1]))
+        {
+        case 1:
+         return \"fldz\";
+       case 2:
+         return \"fld1\";
+       }
+      break;
+
+    case 3: case 4:
+      return \"#\";
+    }
+  abort();
+}"
+  [(set_attr "type" "fmov,fmov,fmov,multi,multi")
+   (set_attr "mode" "XF,XF,XF,SI,SI")])
+
 (define_insn "*movxf_integer"
   [(set (match_operand:XF 0 "nonimmediate_operand" "=f#r,m,f#r,r#f,o")
        (match_operand:XF 1 "general_operand" "fm#r,f#r,G,roF#f,Fr#f"))]
   [(set_attr "type" "fmov,fmov,fmov,multi,multi")
    (set_attr "mode" "XF,XF,XF,SI,SI")])
 
+(define_insn "*movtf_integer"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "=f#r,m,f#r,r#f,o")
+       (match_operand:TF 1 "general_operand" "fm#r,f#r,G,roF#f,Fr#f"))]
+  "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+   && !optimize_size
+   && (reload_in_progress || reload_completed
+       || GET_CODE (operands[1]) != CONST_DOUBLE
+       || memory_operand (operands[0], TFmode))" 
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+      if (REG_P (operands[1])
+          && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+        return \"fstp\\t%y0\";
+      else if (STACK_TOP_P (operands[0]))
+        return \"fld%z1\\t%y1\";
+      else
+        return \"fst\\t%y0\";
+
+    case 1:
+      /* There is no non-popping store to memory for XFmode.  So if
+        we need one, follow the store with a load.  */
+      if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+        return \"fstp%z0\\t%y0\;fld%z0\\t%y0\";
+      else
+        return \"fstp%z0\\t%y0\";
+
+    case 2:
+      switch (standard_80387_constant_p (operands[1]))
+        {
+        case 1:
+         return \"fldz\";
+       case 2:
+         return \"fld1\";
+       }
+      break;
+
+    case 3: case 4:
+      return \"#\";
+    }
+  abort();
+}"
+  [(set_attr "type" "fmov,fmov,fmov,multi,multi")
+   (set_attr "mode" "XF,XF,XF,SI,SI")])
+
 (define_split
-  [(set (match_operand:XF 0 "nonimmediate_operand" "")
-       (match_operand:XF 1 "general_operand" ""))]
+  [(set (match_operand 0 "nonimmediate_operand" "")
+       (match_operand 1 "general_operand" ""))]
   "reload_completed
    && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+   && (GET_MODE (operands[0]) == XFmode || GET_MODE (operands[0]) == TFmode)
    && ! (FP_REG_P (operands[0]) || 
         (GET_CODE (operands[0]) == SUBREG
          && FP_REG_P (SUBREG_REG (operands[0]))))
   "if (ix86_split_long_move (operands)) DONE;")
 
 (define_split
-  [(set (match_operand:XF 0 "register_operand" "")
-       (match_operand:XF 1 "memory_operand" ""))]
+  [(set (match_operand 0 "register_operand" "")
+       (match_operand 1 "memory_operand" ""))]
   "reload_completed
    && GET_CODE (operands[1]) == MEM
+   && (GET_MODE (operands[0]) == XFmode || GET_MODE (operands[0]) == TFmode)
    && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
    && CONSTANT_POOL_ADDRESS_P (XEXP (operands[1], 0))
    && standard_80387_constant_p (get_pool_constant (XEXP (operands[1], 0)))"
 }"
   [(set_attr "type" "fxch")
    (set_attr "mode" "XF")])
+
+(define_insn "swaptf"
+  [(set (match_operand:TF 0 "register_operand" "+f")
+       (match_operand:TF 1 "register_operand" "+f"))
+   (set (match_dup 1)
+       (match_dup 0))]
+  ""
+  "*
+{
+  if (STACK_TOP_P (operands[0]))
+    return \"fxch\\t%1\";
+  else
+    return \"fxch\\t%0\";
+}"
+  [(set_attr "type" "fxch")
+   (set_attr "mode" "XF")])
 \f
 ;; Zero extension instructions
 
        (float_extend:XF (match_operand:SF 1 "register_operand" "")))]
   "FP_REGNO_P (REGNO (operands[1]))"
   [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -12)))
-   (set (mem:DF (reg:SI 7)) (float_extend:XF (match_dup 1)))])
+   (set (mem:XF (reg:SI 7)) (float_extend:XF (match_dup 1)))])
+
+(define_insn "*dummy_extendsftf2"
+  [(set (match_operand:TF 0 "push_operand" "=<")
+       (float_extend:TF (match_operand:SF 1 "nonimmediate_operand" "f")))]
+  "0"
+  "#")
+
+(define_split
+  [(set (match_operand:TF 0 "push_operand" "")
+       (float_extend:TF (match_operand:SF 1 "register_operand" "")))]
+  "FP_REGNO_P (REGNO (operands[1]))"
+  [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -16)))
+   (set (mem:TF (reg:SI 7)) (float_extend:XF (match_dup 1)))])
 
 (define_insn "*dummy_extenddfxf2"
   [(set (match_operand:XF 0 "push_operand" "=<")
        (float_extend:XF (match_operand:DF 1 "register_operand" "")))]
   "FP_REGNO_P (REGNO (operands[1]))"
   [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -12)))
-   (set (mem:DF (reg:SI 7)) (float_extend:XF (match_dup 1)))])
+   (set (mem:XF (reg:SI 7)) (float_extend:XF (match_dup 1)))])
+
+(define_insn "*dummy_extenddftf2"
+  [(set (match_operand:TF 0 "push_operand" "=<")
+       (float_extend:TF (match_operand:DF 1 "nonimmediate_operand" "f")))]
+  "0"
+  "#")
+
+(define_split
+  [(set (match_operand:TF 0 "push_operand" "")
+       (float_extend:TF (match_operand:DF 1 "register_operand" "")))]
+  "FP_REGNO_P (REGNO (operands[1]))"
+  [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -16)))
+   (set (mem:TF (reg:SI 7)) (float_extend:XF (match_dup 1)))])
 
 (define_expand "extendsfdf2"
   [(set (match_operand:DF 0 "nonimmediate_operand" "")
   [(set_attr "type" "fmov")
    (set_attr "mode" "SF,XF")])
 
+(define_expand "extendsftf2"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "")
+        (float_extend:TF (match_operand:SF 1 "nonimmediate_operand" "")))]
+  "TARGET_80387"
+  "
+{
+  if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
+    operands[1] = force_reg (SFmode, operands[1]);
+}")
+
+(define_insn "*extendsftf2_1"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "=f,m")
+        (float_extend:TF (match_operand:SF 1 "nonimmediate_operand" "fm,f")))]
+  "TARGET_80387
+   && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+      if (REG_P (operands[1])
+          && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+        return \"fstp\\t%y0\";
+      else if (STACK_TOP_P (operands[0]))
+        return \"fld%z1\\t%y1\";
+      else
+        return \"fst\\t%y0\";
+
+    case 1:
+      /* There is no non-popping store to memory for XFmode.  So if
+        we need one, follow the store with a load.  */
+      if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+        return \"fstp%z0\\t%y0\\n\\tfld%z0\\t%y0\";
+      else
+        return \"fstp%z0\\t%y0\";
+
+    default:
+      abort ();
+    }
+}"
+  [(set_attr "type" "fmov")
+   (set_attr "mode" "SF,XF")])
+
 (define_expand "extenddfxf2"
   [(set (match_operand:XF 0 "nonimmediate_operand" "")
         (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "")))]
   [(set_attr "type" "fmov")
    (set_attr "mode" "DF,XF")])
 
+(define_expand "extenddftf2"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "")
+        (float_extend:TF (match_operand:DF 1 "nonimmediate_operand" "")))]
+  "TARGET_80387"
+  "
+{
+  if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
+    operands[1] = force_reg (DFmode, operands[1]);
+}")
+
+(define_insn "*extenddftf2_1"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "=f,m")
+        (float_extend:TF (match_operand:DF 1 "nonimmediate_operand" "fm,f")))]
+  "TARGET_80387
+   && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+      if (REG_P (operands[1])
+          && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+        return \"fstp\\t%y0\";
+      else if (STACK_TOP_P (operands[0]))
+        return \"fld%z1\\t%y1\";
+      else
+        return \"fst\\t%y0\";
+
+    case 1:
+      /* There is no non-popping store to memory for XFmode.  So if
+        we need one, follow the store with a load.  */
+      if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+        return \"fstp%z0\\t%y0\\n\\tfld%z0\\t%y0\";
+      else
+        return \"fstp%z0\\t%y0\";
+
+    default:
+      abort ();
+    }
+}"
+  [(set_attr "type" "fmov")
+   (set_attr "mode" "DF,XF")])
+
 ;; %%% This seems bad bad news.
 ;; This cannot output into an f-reg because there is no way to be sure
 ;; of truncating in that case.  Otherwise this is just like a simple move
    (set (match_dup 0) (match_dup 2))]
   "")
 
+(define_expand "trunctfsf2"
+  [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "")
+                  (float_truncate:SF
+                   (match_operand:TF 1 "register_operand" "")))
+             (clobber (match_dup 2))])]
+  "TARGET_80387"
+  "operands[2] = assign_386_stack_local (SFmode, 0);")
+
+(define_insn "*trunctfsf2_1"
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=m,f")
+       (float_truncate:SF
+        (match_operand:TF 1 "register_operand" "f,0")))
+   (clobber (match_operand:SF 2 "memory_operand" "=m,m"))]
+  "TARGET_80387"
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+       return \"fstp%z0\\t%y0\";
+      else
+       return \"fst%z0\\t%y0\";
+    case 1:
+      return \"fstp%z2\\t%y2\;fld%z2\\t%y2\";
+    }
+  abort ();
+}"
+  [(set_attr "type" "fmov,multi")
+   (set_attr "mode" "SF")])
+
+(define_insn "*truncxfsf2_2"
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=m")
+       (float_truncate:SF
+        (match_operand:TF 1 "register_operand" "f")))]
+  "TARGET_80387"
+  "*
+{
+  if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+    return \"fstp%z0\\t%y0\";
+  else
+    return \"fst%z0\\t%y0\";
+}"
+  [(set_attr "type" "fmov")
+   (set_attr "mode" "SF")])
+
+(define_split
+  [(set (match_operand:SF 0 "memory_operand" "")
+       (float_truncate:SF
+        (match_operand:TF 1 "register_operand" "")))
+   (clobber (match_operand:SF 2 "memory_operand" ""))]
+  "TARGET_80387"
+  [(set (match_dup 0) (float_truncate:SF (match_dup 1)))]
+  "")
+
+(define_split
+  [(set (match_operand:SF 0 "register_operand" "")
+       (float_truncate:SF
+        (match_operand:TF 1 "register_operand" "")))
+   (clobber (match_operand:SF 2 "memory_operand" ""))]
+  "TARGET_80387 && reload_completed"
+  [(set (match_dup 2) (float_truncate:SF (match_dup 1)))
+   (set (match_dup 0) (match_dup 2))]
+  "")
+
+
 (define_expand "truncxfdf2"
   [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "")
                   (float_truncate:DF
    (set (match_dup 0) (match_dup 2))]
   "")
 
+(define_expand "trunctfdf2"
+  [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "")
+                  (float_truncate:DF
+                   (match_operand:TF 1 "register_operand" "")))
+             (clobber (match_dup 2))])]
+  "TARGET_80387"
+  "operands[2] = assign_386_stack_local (DFmode, 0);")
+
+(define_insn "*trunctfdf2_1"
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=m,f")
+       (float_truncate:DF
+        (match_operand:TF 1 "register_operand" "f,0")))
+   (clobber (match_operand:DF 2 "memory_operand" "=m,m"))]
+  "TARGET_80387"
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+       return \"fstp%z0\\t%y0\";
+      else
+       return \"fst%z0\\t%y0\";
+    case 1:
+      return \"fstp%z2\\t%y2\;fld%z2\\t%y2\";
+    }
+  abort ();
+}"
+  [(set_attr "type" "fmov,multi")
+   (set_attr "mode" "DF")])
+
+(define_insn "*truncxfdf2_2"
+  [(set (match_operand:DF 0 "memory_operand" "=m")
+       (float_truncate:DF
+         (match_operand:TF 1 "register_operand" "f")))]
+  "TARGET_80387"
+  "*
+{
+  if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+    return \"fstp%z0\\t%y0\";
+  else
+    return \"fst%z0\\t%y0\";
+}"
+  [(set_attr "type" "fmov")
+   (set_attr "mode" "DF")])
+
+(define_split
+  [(set (match_operand:DF 0 "memory_operand" "")
+       (float_truncate:DF
+        (match_operand:TF 1 "register_operand" "")))
+   (clobber (match_operand:DF 2 "memory_operand" ""))]
+  "TARGET_80387"
+  [(set (match_dup 0) (float_truncate:DF (match_dup 1)))]
+  "")
+
+(define_split
+  [(set (match_operand:DF 0 "register_operand" "")
+       (float_truncate:DF
+        (match_operand:TF 1 "register_operand" "")))
+   (clobber (match_operand:DF 2 "memory_operand" ""))]
+  "TARGET_80387 && reload_completed"
+  [(set (match_dup 2) (float_truncate:DF (match_dup 1)))
+   (set (match_dup 0) (match_dup 2))]
+  "")
+
 \f
 ;; %%% Break up all these bad boys.
 
 ;; Signed conversion to DImode.
 
-(define_expand "fix_truncxfdi2"
+(define_expand "fix_truncxfdi2"
+  [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
+                  (fix:DI (match_operand:XF 1 "register_operand" "")))
+             (clobber (match_dup 2))
+             (clobber (match_dup 3))
+             (clobber (match_scratch:SI 4 ""))
+             (clobber (match_scratch:XF 5 ""))])]
+  "TARGET_80387"
+  "operands[2] = assign_386_stack_local (SImode, 0);
+   operands[3] = assign_386_stack_local (DImode, 1);")
+
+(define_expand "fix_trunctfdi2"
   [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
-                  (fix:DI (match_operand:XF 1 "register_operand" "")))
+                  (fix:DI (match_operand:TF 1 "register_operand" "")))
              (clobber (match_dup 2))
              (clobber (match_dup 3))
              (clobber (match_scratch:SI 4 ""))
-             (clobber (match_scratch:XF 5 ""))])]
+             (clobber (match_scratch:TF 5 ""))])]
   "TARGET_80387"
   "operands[2] = assign_386_stack_local (SImode, 0);
    operands[3] = assign_386_stack_local (DImode, 1);")
   "operands[2] = assign_386_stack_local (SImode, 0);
    operands[3] = assign_386_stack_local (SImode, 1);")
 
+(define_expand "fix_trunctfsi2"
+  [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
+                  (fix:SI (match_operand:TF 1 "register_operand" "")))
+             (clobber (match_dup 2))
+             (clobber (match_dup 3))
+             (clobber (match_scratch:SI 4 ""))])]
+  "TARGET_80387"
+  "operands[2] = assign_386_stack_local (SImode, 0);
+   operands[3] = assign_386_stack_local (SImode, 1);")
+
 (define_expand "fix_truncdfsi2"
   [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
                   (fix:SI (match_operand:DF 1 "register_operand" "")))
   "operands[2] = assign_386_stack_local (SImode, 0);
    operands[3] = assign_386_stack_local (HImode, 1);")
 
+(define_expand "fix_trunctfhi2"
+  [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
+                  (fix:HI (match_operand:TF 1 "register_operand" "")))
+             (clobber (match_dup 2))
+             (clobber (match_dup 3))
+             (clobber (match_scratch:SI 4 ""))])]
+  "TARGET_80387"
+  "operands[2] = assign_386_stack_local (SImode, 0);
+   operands[3] = assign_386_stack_local (HImode, 1);")
+
 (define_expand "fix_truncdfhi2"
   [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
                   (fix:HI (match_operand:DF 1 "register_operand" "")))
    (set_attr "mode" "XF")
    (set_attr "fp_int_src" "true")])
 
+(define_insn "floathitf2"
+  [(set (match_operand:TF 0 "register_operand" "=f,f")
+       (float:TF (match_operand:HI 1 "nonimmediate_operand" "m,r")))]
+  "TARGET_80387"
+  "@
+   fild%z1\\t%1
+   #"
+  [(set_attr "type" "fmov,multi")
+   (set_attr "mode" "XF")
+   (set_attr "fp_int_src" "true")])
+
 (define_insn "floatsixf2"
   [(set (match_operand:XF 0 "register_operand" "=f,f")
        (float:XF (match_operand:SI 1 "nonimmediate_operand" "m,r")))]
    (set_attr "mode" "XF")
    (set_attr "fp_int_src" "true")])
 
+(define_insn "floatsitf2"
+  [(set (match_operand:TF 0 "register_operand" "=f,f")
+       (float:TF (match_operand:SI 1 "nonimmediate_operand" "m,r")))]
+  "TARGET_80387"
+  "@
+   fild%z1\\t%1
+   #"
+  [(set_attr "type" "fmov,multi")
+   (set_attr "mode" "XF")
+   (set_attr "fp_int_src" "true")])
+
 (define_insn "floatdixf2"
   [(set (match_operand:XF 0 "register_operand" "=f,f")
        (float:XF (match_operand:DI 1 "nonimmediate_operand" "m,r")))]
    (set_attr "mode" "XF")
    (set_attr "fp_int_src" "true")])
 
+(define_insn "floatditf2"
+  [(set (match_operand:TF 0 "register_operand" "=f,f")
+       (float:TF (match_operand:DI 1 "nonimmediate_operand" "m,r")))]
+  "TARGET_80387"
+  "@
+   fild%z1\\t%1
+   #"
+  [(set_attr "type" "fmov,multi")
+   (set_attr "mode" "XF")
+   (set_attr "fp_int_src" "true")])
+
 ;; %%% Kill these when reload knows how to do it.
 (define_split
   [(set (match_operand 0 "register_operand" "")
   "TARGET_80387"
   "")
 
+(define_expand "addtf3"
+  [(set (match_operand:TF 0 "register_operand" "")
+       (plus:TF (match_operand:TF 1 "register_operand" "")
+                (match_operand:TF 2 "register_operand" "")))]
+  "TARGET_80387"
+  "")
+
 (define_expand "adddf3"
   [(set (match_operand:DF 0 "register_operand" "")
        (plus:DF (match_operand:DF 1 "register_operand" "")
   "TARGET_80387"
   "")
 
+(define_expand "subtf3"
+  [(set (match_operand:TF 0 "register_operand" "")
+       (minus:TF (match_operand:TF 1 "register_operand" "")
+                 (match_operand:TF 2 "register_operand" "")))]
+  "TARGET_80387"
+  "")
+
 (define_expand "subdf3"
   [(set (match_operand:DF 0 "register_operand" "")
        (minus:DF (match_operand:DF 1 "register_operand" "")
   "TARGET_80387"
   "")
 
+(define_expand "multf3"
+  [(set (match_operand:TF 0 "register_operand" "")
+       (mult:TF (match_operand:TF 1 "register_operand" "")
+                (match_operand:TF 2 "register_operand" "")))]
+  "TARGET_80387"
+  "")
+
 (define_expand "muldf3"
   [(set (match_operand:DF 0 "register_operand" "")
        (mult:DF (match_operand:DF 1 "register_operand" "")
   "TARGET_80387"
   "")
 
+(define_expand "divtf3"
+  [(set (match_operand:TF 0 "register_operand" "")
+       (div:TF (match_operand:TF 1 "register_operand" "")
+               (match_operand:TF 2 "register_operand" "")))]
+  "TARGET_80387"
+  "")
+
 (define_expand "divdf3"
   [(set (match_operand:DF 0 "register_operand" "")
        (div:DF (match_operand:DF 1 "register_operand" "")
   "TARGET_80387"
   "ix86_expand_unary_operator (NEG, XFmode, operands); DONE;")
 
+(define_expand "negtf2"
+  [(parallel [(set (match_operand:TF 0 "nonimmediate_operand" "")
+                  (neg:TF (match_operand:TF 1 "nonimmediate_operand" "")))
+             (clobber (reg:CC 17))])]
+  "TARGET_80387"
+  "ix86_expand_unary_operator (NEG, TFmode, operands); DONE;")
+
 ;; Keep 'f' and 'r' in separate alternatives to avoid reload problems
 ;; because of secondary memory needed to reload from class FLOAT_INT_REGS
 ;; to itself.
   "operands[1] = GEN_INT (0x8000);
    operands[0] = gen_rtx_REG (SImode, true_regnum (operands[0]) + 2);")
 
+;; Keep 'f' and 'r' in separate alternatives to avoid reload problems
+;; because of secondary memory needed to reload from class FLOAT_INT_REGS
+;; to itself.
+(define_insn "*negtf2_if"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "=f#r,rm#f")
+       (neg:TF (match_operand:TF 1 "nonimmediate_operand" "0,0")))
+   (clobber (reg:CC 17))]
+  "TARGET_80387 && ix86_unary_operator_ok (NEG, TFmode, operands)"
+  "#")
+
+(define_split
+  [(set (match_operand:TF 0 "register_operand" "")
+       (neg:TF (match_operand:TF 1 "register_operand" "")))
+   (clobber (reg:CC 17))]
+  "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed"
+  [(set (match_dup 0)
+       (neg:TF (match_dup 1)))]
+  "")
+
+(define_split
+  [(set (match_operand:TF 0 "register_operand" "")
+       (neg:TF (match_operand:TF 1 "register_operand" "")))
+   (clobber (reg:CC 17))]
+  "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))"
+  [(parallel [(set (match_dup 0) (xor:SI (match_dup 0) (match_dup 1)))
+             (clobber (reg:CC 17))])]
+  "operands[1] = GEN_INT (0x8000);
+   operands[0] = gen_rtx_REG (SImode, true_regnum (operands[0]) + 2);")
+
 ;; Conditionize these after reload. If they matches before reload, we 
 ;; lose the clobber and ability to use integer instructions.
 
   [(set_attr "type" "fsgn")
    (set_attr "mode" "XF")
    (set_attr "ppro_uops" "few")])
+
+(define_insn "*negtf2_1"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+       (neg:TF (match_operand:TF 1 "register_operand" "0")))]
+  "TARGET_80387 && reload_completed"
+  "fchs"
+  [(set_attr "type" "fsgn")
+   (set_attr "mode" "XF")
+   (set_attr "ppro_uops" "few")])
+
+(define_insn "*negextenddftf2"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+       (neg:TF (float_extend:TF
+                 (match_operand:DF 1 "register_operand" "0"))))]
+  "TARGET_80387"
+  "fchs"
+  [(set_attr "type" "fsgn")
+   (set_attr "mode" "XF")
+   (set_attr "ppro_uops" "few")])
+
+(define_insn "*negextendsftf2"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+       (neg:TF (float_extend:TF
+                 (match_operand:SF 1 "register_operand" "0"))))]
+  "TARGET_80387"
+  "fchs"
+  [(set_attr "type" "fsgn")
+   (set_attr "mode" "XF")
+   (set_attr "ppro_uops" "few")])
 \f
 ;; Absolute value instructions
 
   "TARGET_80387"
   "ix86_expand_unary_operator (ABS, XFmode, operands); DONE;")
 
+(define_expand "abstf2"
+  [(parallel [(set (match_operand:TF 0 "nonimmediate_operand" "")
+                  (neg:TF (match_operand:TF 1 "nonimmediate_operand" "")))
+             (clobber (reg:CC 17))])]
+  "TARGET_80387"
+  "ix86_expand_unary_operator (ABS, TFmode, operands); DONE;")
+
 ;; Keep 'f' and 'r' in separate alternatives to avoid reload problems
 ;; because of secondary memory needed to reload from class FLOAT_INT_REGS
 ;; to itself.
   "operands[1] = GEN_INT (~0x8000);
    operands[0] = gen_rtx_REG (SImode, true_regnum (operands[0]) + 2);")
 
+(define_insn "*abstf2_if"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "=f#r,rm#f")
+       (abs:TF (match_operand:TF 1 "nonimmediate_operand" "0,0")))
+   (clobber (reg:CC 17))]
+  "TARGET_80387 && ix86_unary_operator_ok (ABS, TFmode, operands)"
+  "#")
+
+(define_split
+  [(set (match_operand:TF 0 "register_operand" "")
+       (abs:TF (match_operand:TF 1 "register_operand" "")))
+   (clobber (reg:CC 17))]
+  "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed"
+  [(set (match_dup 0)
+       (abs:TF (match_dup 1)))]
+  "")
+
+(define_split
+  [(set (match_operand:TF 0 "register_operand" "")
+       (abs:TF (match_operand:TF 1 "register_operand" "")))
+   (clobber (reg:CC 17))]
+  "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))"
+  [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (match_dup 1)))
+             (clobber (reg:CC 17))])]
+  "operands[1] = GEN_INT (~0x8000);
+   operands[0] = gen_rtx_REG (SImode, true_regnum (operands[0]) + 2);")
+
 (define_insn "*abssf2_1"
   [(set (match_operand:SF 0 "register_operand" "=f")
        (abs:SF (match_operand:SF 1 "register_operand" "0")))]
   "fabs"
   [(set_attr "type" "fsgn")
    (set_attr "mode" "XF")])
+
+(define_insn "*abstf2_1"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+       (abs:TF (match_operand:TF 1 "register_operand" "0")))]
+  "TARGET_80387 && reload_completed"
+  "fabs"
+  [(set_attr "type" "fsgn")
+   (set_attr "mode" "DF")])
+
+(define_insn "*absextenddftf2"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+       (abs:TF (float_extend:TF
+         (match_operand:DF 1 "register_operand" "0"))))]
+  "TARGET_80387"
+  "fabs"
+  [(set_attr "type" "fsgn")
+   (set_attr "mode" "XF")])
+
+(define_insn "*absextendsftf2"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+       (abs:TF (float_extend:TF
+         (match_operand:SF 1 "register_operand" "0"))))]
+  "TARGET_80387"
+  "fabs"
+  [(set_attr "type" "fsgn")
+   (set_attr "mode" "XF")])
 \f
 ;; One complement instructions
 
            (const_string "fop")))
    (set_attr "mode" "XF")])
 
+(define_insn "*fop_tf_comm"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+       (match_operator:TF 3 "binary_fp_operator"
+                       [(match_operand:TF 1 "register_operand" "%0")
+                        (match_operand:TF 2 "register_operand" "f")]))]
+  "TARGET_80387 && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c'"
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (if_then_else (match_operand:TF 3 "mult_operator" "") 
+           (const_string "fmul")
+           (const_string "fop")))
+   (set_attr "mode" "XF")])
+
 (define_insn "*fop_sf_1"
   [(set (match_operand:SF 0 "register_operand" "=f,f")
        (match_operator:SF 3 "binary_fp_operator"
               (const_string "fop")))
    (set_attr "mode" "XF")])
 
+(define_insn "*fop_tf_1"
+  [(set (match_operand:TF 0 "register_operand" "=f,f")
+       (match_operator:TF 3 "binary_fp_operator"
+                       [(match_operand:TF 1 "register_operand" "0,f")
+                        (match_operand:TF 2 "register_operand" "f,0")]))]
+  "TARGET_80387
+   && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c'"
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:TF 3 "mult_operator" "") 
+                 (const_string "fmul")
+               (match_operand:TF 3 "div_operator" "") 
+                 (const_string "fdiv")
+              ]
+              (const_string "fop")))
+   (set_attr "mode" "XF")])
+
 (define_insn "*fop_xf_2"
   [(set (match_operand:XF 0 "register_operand" "=f,f")
        (match_operator:XF 3 "binary_fp_operator"
    (set_attr "mode" "SI")
    (set_attr "ppro_uops" "many")])
 
+(define_insn "*fop_tf_2"
+  [(set (match_operand:TF 0 "register_operand" "=f,f")
+       (match_operator:TF 3 "binary_fp_operator"
+          [(float:TF (match_operand:SI 1 "nonimmediate_operand" "m,?r"))
+           (match_operand:TF 2 "register_operand" "0,0")]))]
+  "TARGET_80387 && TARGET_USE_FIOP"
+  "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:TF 3 "mult_operator" "") 
+                 (const_string "fmul")
+               (match_operand:TF 3 "div_operator" "") 
+                 (const_string "fdiv")
+              ]
+              (const_string "fop")))
+   (set_attr "fp_int_src" "true")
+   (set_attr "mode" "SI")
+   (set_attr "ppro_uops" "many")])
+
 (define_insn "*fop_xf_3"
   [(set (match_operand:XF 0 "register_operand" "=f,f")
        (match_operator:XF 3 "binary_fp_operator"
    (set_attr "mode" "SI")
    (set_attr "ppro_uops" "many")])
 
+(define_insn "*fop_tf_3"
+  [(set (match_operand:TF 0 "register_operand" "=f,f")
+       (match_operator:TF 3 "binary_fp_operator"
+         [(match_operand:TF 1 "register_operand" "0,0")
+          (float:TF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))]
+  "TARGET_80387 && TARGET_USE_FIOP"
+  "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:TF 3 "mult_operator" "") 
+                 (const_string "fmul")
+               (match_operand:TF 3 "div_operator" "") 
+                 (const_string "fdiv")
+              ]
+              (const_string "fop")))
+   (set_attr "fp_int_src" "true")
+   (set_attr "mode" "SI")
+   (set_attr "ppro_uops" "many")])
+
 (define_insn "*fop_xf_4"
   [(set (match_operand:XF 0 "register_operand" "=f,f")
        (match_operator:XF 3 "binary_fp_operator"
               (const_string "fop")))
    (set_attr "mode" "SF")])
 
+(define_insn "*fop_tf_4"
+  [(set (match_operand:TF 0 "register_operand" "=f,f")
+       (match_operator:TF 3 "binary_fp_operator"
+          [(float_extend:TF (match_operand:SF 1 "nonimmediate_operand" "fm,0"))
+           (match_operand:TF 2 "register_operand" "0,f")]))]
+  "TARGET_80387"
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:TF 3 "mult_operator" "") 
+                 (const_string "fmul")
+               (match_operand:TF 3 "div_operator" "") 
+                 (const_string "fdiv")
+              ]
+              (const_string "fop")))
+   (set_attr "mode" "SF")])
+
 (define_insn "*fop_xf_5"
   [(set (match_operand:XF 0 "register_operand" "=f,f")
        (match_operator:XF 3 "binary_fp_operator"
               (const_string "fop")))
    (set_attr "mode" "SF")])
 
+(define_insn "*fop_tf_5"
+  [(set (match_operand:TF 0 "register_operand" "=f,f")
+       (match_operator:TF 3 "binary_fp_operator"
+         [(match_operand:TF 1 "register_operand" "0,f")
+          (float_extend:TF
+           (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
+  "TARGET_80387"
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:TF 3 "mult_operator" "") 
+                 (const_string "fmul")
+               (match_operand:TF 3 "div_operator" "") 
+                 (const_string "fdiv")
+              ]
+              (const_string "fop")))
+   (set_attr "mode" "SF")])
+
 (define_insn "*fop_xf_6"
   [(set (match_operand:XF 0 "register_operand" "=f,f")
        (match_operator:XF 3 "binary_fp_operator"
               (const_string "fop")))
    (set_attr "mode" "DF")])
 
+(define_insn "*fop_tf_6"
+  [(set (match_operand:TF 0 "register_operand" "=f,f")
+       (match_operator:TF 3 "binary_fp_operator"
+          [(float_extend:TF (match_operand:DF 1 "nonimmediate_operand" "fm,0"))
+           (match_operand:TF 2 "register_operand" "0,f")]))]
+  "TARGET_80387"
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:TF 3 "mult_operator" "") 
+                 (const_string "fmul")
+               (match_operand:TF 3 "div_operator" "") 
+                 (const_string "fdiv")
+              ]
+              (const_string "fop")))
+   (set_attr "mode" "DF")])
+
 (define_insn "*fop_xf_7"
   [(set (match_operand:XF 0 "register_operand" "=f,f")
        (match_operator:XF 3 "binary_fp_operator"
               (const_string "fop")))
    (set_attr "mode" "DF")])
 
+(define_insn "*fop_tf_7"
+  [(set (match_operand:TF 0 "register_operand" "=f,f")
+       (match_operator:TF 3 "binary_fp_operator"
+         [(match_operand:TF 1 "register_operand" "0,f")
+          (float_extend:TF
+           (match_operand:DF 2 "nonimmediate_operand" "fm,0"))]))]
+  "TARGET_80387"
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:TF 3 "mult_operator" "") 
+                 (const_string "fmul")
+               (match_operand:TF 3 "div_operator" "") 
+                 (const_string "fdiv")
+              ]
+              (const_string "fop")))
+   (set_attr "mode" "DF")])
+
 (define_split
   [(set (match_operand 0 "register_operand" "")
        (match_operator 3 "binary_fp_operator"
    (set_attr "mode" "XF")
    (set_attr "athlon_decode" "direct")])
 
+(define_insn "sqrttf2"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+       (sqrt:TF (match_operand:TF 1 "register_operand" "0")))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && (TARGET_IEEE_FP || flag_fast_math) "
+  "fsqrt"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "XF")
+   (set_attr "athlon_decode" "direct")])
+
 (define_insn "*sqrtextenddfxf2"
   [(set (match_operand:XF 0 "register_operand" "=f")
        (sqrt:XF (float_extend:XF
    (set_attr "mode" "XF")
    (set_attr "athlon_decode" "direct")])
 
+(define_insn "*sqrtextenddftf2"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+       (sqrt:TF (float_extend:TF
+                 (match_operand:DF 1 "register_operand" "0"))))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
+  "fsqrt"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "XF")
+   (set_attr "athlon_decode" "direct")])
+
 (define_insn "*sqrtextendsfxf2"
   [(set (match_operand:XF 0 "register_operand" "=f")
        (sqrt:XF (float_extend:XF
    (set_attr "mode" "XF")
    (set_attr "athlon_decode" "direct")])
 
+(define_insn "*sqrtextendsftf2"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+       (sqrt:TF (float_extend:TF
+                 (match_operand:SF 1 "register_operand" "0"))))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
+  "fsqrt"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "XF")
+   (set_attr "athlon_decode" "direct")])
+
 (define_insn "sindf2"
   [(set (match_operand:DF 0 "register_operand" "=f")
        (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))]
   [(set_attr "type" "fpspc")
    (set_attr "mode" "XF")])
 
+(define_insn "sintf2"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+       (unspec:TF [(match_operand:TF 1 "register_operand" "0")] 1))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
+  "fsin"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "XF")])
+
 (define_insn "cosdf2"
   [(set (match_operand:DF 0 "register_operand" "=f")
        (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 2))]
   "fcos"
   [(set_attr "type" "fpspc")
    (set_attr "mode" "XF")])
+
+(define_insn "costf2"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+       (unspec:TF [(match_operand:TF 1 "register_operand" "0")] 2))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
+  "fcos"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "XF")])
 \f
 ;; Block operation instructions
 
   "TARGET_CMOVE"
   "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;")
 
+(define_expand "movtfcc"
+  [(set (match_operand:TF 0 "register_operand" "")
+       (if_then_else:TF (match_operand 1 "comparison_operator" "")
+                        (match_operand:TF 2 "register_operand" "")
+                        (match_operand:TF 3 "register_operand" "")))]
+  "TARGET_CMOVE"
+  "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;")
+
 (define_insn "*movxfcc_1"
   [(set (match_operand:XF 0 "register_operand" "=f,f")
        (if_then_else:XF (match_operator 1 "fcmov_comparison_operator" 
    fcmov%f1\\t{%3, %0|%0, %3}"
   [(set_attr "type" "fcmov")
    (set_attr "mode" "XF")])
+
+(define_insn "*movtfcc_1"
+  [(set (match_operand:TF 0 "register_operand" "=f,f")
+       (if_then_else:TF (match_operator 1 "fcmov_comparison_operator" 
+                               [(reg 17) (const_int 0)])
+                     (match_operand:TF 2 "register_operand" "f,0")
+                     (match_operand:TF 3 "register_operand" "0,f")))]
+  "TARGET_CMOVE"
+  "@
+   fcmov%F1\\t{%2, %0|%0, %2}
+   fcmov%f1\\t{%3, %0|%0, %3}"
+  [(set_attr "type" "fcmov")
+   (set_attr "mode" "XF")])
 \f
 ;; Misc patterns (?)
 
index 4d37992..c8cdb1a 100644 (file)
@@ -446,7 +446,8 @@ in the following sections.
 -malign-jumps=@var{num}  -malign-loops=@var{num}
 -malign-functions=@var{num} -mpreferred-stack-boundary=@var{num}
 -mthreads -mno-align-stringops -minline-all-stringops
--mpush-args -maccumulate-outgoing-args
+-mpush-args -maccumulate-outgoing-args -m128bit-long-double
+-m96bit-long-double
 
 @emph{HPPA Options}
 -march=@var{architecture type}
@@ -6344,9 +6345,22 @@ boundary.  Aligning @code{double} variables on a two word boundary will
 produce code that runs somewhat faster on a @samp{Pentium} at the
 expense of more memory.
 
-@strong{Warning:} if you use the @samp{-malign-double} switch,
-structures containing the above types will be aligned differently than
-the published application binary interface specifications for the 386.
+@item -m128bit-long-double
+@itemx -m128bit-long-double
+Control the size of @code{long double} type. i386 application binary interface
+specify the size to be 12 bytes, while modern architectures (Pentium and newer)
+preffer @code{long double} aligned to 8 or 16 byte boundary.  This is
+impossible to reach with 12 byte long doubles in the array accesses.
+
+@strong{Warning:} if you use the @samp{-m128bit-long-double} switch, the
+structures and arrays containing @code{long double} will change their size as
+well as function calling convention for function taking @code{long double}
+will be modified. 
+
+@item -m96bit-long-double
+@itemx -m96bit-long-double
+Set the size of @code{long double} to 96 bytes as requires by the i386
+application binary interface.  This is the default.
 
 @item -msvr3-shlib
 @itemx -mno-svr3-shlib