aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2001-01-02 20:24:27 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2001-01-02 19:24:27 +0000
commit2b589241d86c1f2e68d5f2dbceb60f19050bd199 (patch)
tree01c459d5b2a2b1fe5b1b1822b129430cdc4b1578
parent9e1458e7d76099127b7991efb60ec26952318e4b (diff)
downloadgcc-2b589241d86c1f2e68d5f2dbceb60f19050bd199.zip
gcc-2b589241d86c1f2e68d5f2dbceb60f19050bd199.tar.gz
gcc-2b589241d86c1f2e68d5f2dbceb60f19050bd199.tar.bz2
i386.c (ix86_split_to_parts): Return number of part required; handle TFmodes.
* 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. From-SVN: r38633
-rw-r--r--gcc/ChangeLog25
-rw-r--r--gcc/config/i386/i386.c34
-rw-r--r--gcc/config/i386/i386.h45
-rw-r--r--gcc/config/i386/i386.md911
-rw-r--r--gcc/invoke.texi22
5 files changed, 992 insertions, 45 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 884a4be..f64a007 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 3bd1b81..c8a25c4 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -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;
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 4f59fb8..8f219cf 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -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;
/* 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. */
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 72954bf..836edc5 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -373,19 +373,15 @@
(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
@@ -833,8 +829,8 @@
(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")))
@@ -929,7 +925,8 @@
(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
@@ -1255,6 +1252,18 @@
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" "")
@@ -1370,6 +1379,16 @@
[(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
@@ -1381,6 +1400,17 @@
[(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
@@ -2428,6 +2458,12 @@
""
"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
@@ -2464,6 +2500,35 @@
[(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"))]
@@ -2492,10 +2557,41 @@
[(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;")
@@ -2507,6 +2603,13 @@
[(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")
@@ -2555,6 +2658,53 @@
[(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"))]
@@ -2602,11 +2752,59 @@
[(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]))))
@@ -2619,10 +2817,11 @@
"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)))"
@@ -2645,6 +2844,22 @@
}"
[(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")])
;; Zero extension instructions
@@ -3033,7 +3248,20 @@
(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" "=<")
@@ -3046,7 +3274,20 @@
(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" "")
@@ -3133,6 +3374,49 @@
[(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" "")))]
@@ -3176,6 +3460,49 @@
[(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
@@ -3312,6 +3639,72 @@
(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
@@ -3377,6 +3770,71 @@
(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))]
+ "")
+
;; %%% Break up all these bad boys.
@@ -3393,6 +3851,17 @@
"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:TF 1 "register_operand" "")))
+ (clobber (match_dup 2))
+ (clobber (match_dup 3))
+ (clobber (match_scratch:SI 4 ""))
+ (clobber (match_scratch:TF 5 ""))])]
+ "TARGET_80387"
+ "operands[2] = assign_386_stack_local (SImode, 0);
+ operands[3] = assign_386_stack_local (DImode, 1);")
+
(define_expand "fix_truncdfdi2"
[(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
(fix:DI (match_operand:DF 1 "register_operand" "")))
@@ -3454,6 +3923,16 @@
"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" "")))
@@ -3510,6 +3989,16 @@
"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" "")))
@@ -3658,6 +4147,17 @@
(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")))]
@@ -3669,6 +4169,17 @@
(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")))]
@@ -3680,6 +4191,17 @@
(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" "")
@@ -4733,6 +5255,13 @@
"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" "")
@@ -4931,6 +5460,13 @@
"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" "")
@@ -5105,6 +5641,13 @@
"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" "")
@@ -5152,6 +5695,13 @@
"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" "")
@@ -6381,6 +6931,13 @@
"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.
@@ -6410,6 +6967,35 @@
"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.
@@ -6469,6 +7055,35 @@
[(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")])
;; Absolute value instructions
@@ -6570,6 +7185,13 @@
"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.
@@ -6599,6 +7221,32 @@
"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")))]
@@ -6649,6 +7297,32 @@
"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")])
;; One complement instructions
@@ -9345,6 +10019,19 @@
(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"
@@ -9504,6 +10191,23 @@
(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"
@@ -9522,6 +10226,24 @@
(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"
@@ -9540,6 +10262,24 @@
(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"
@@ -9556,6 +10296,22 @@
(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"
@@ -9573,6 +10329,23 @@
(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"
@@ -9589,6 +10362,22 @@
(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"
@@ -9606,6 +10395,23 @@
(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"
@@ -9689,6 +10495,16 @@
(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
@@ -9699,6 +10515,16 @@
(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
@@ -9709,6 +10535,16 @@
(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))]
@@ -9742,6 +10578,14 @@
[(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))]
@@ -9774,6 +10618,14 @@
"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")])
;; Block operation instructions
@@ -10712,6 +11564,14 @@
"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"
@@ -10724,6 +11584,19 @@
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")])
;; Misc patterns (?)
diff --git a/gcc/invoke.texi b/gcc/invoke.texi
index 4d37992..c8cdb1a 100644
--- a/gcc/invoke.texi
+++ b/gcc/invoke.texi
@@ -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