From 2b589241d86c1f2e68d5f2dbceb60f19050bd199 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Tue, 2 Jan 2001 20:24:27 +0100 Subject: [PATCH] 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 --- gcc/ChangeLog | 25 ++ gcc/config/i386/i386.c | 34 +- gcc/config/i386/i386.h | 45 +- gcc/config/i386/i386.md | 917 +++++++++++++++++++++++++++++++++++++++- gcc/invoke.texi | 22 +- 5 files changed, 995 insertions(+), 48 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 884a4befc61..f64a0073ba6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,28 @@ +Tue Jan 2 20:21:31 MET 2001 Jan Hubicka + + * 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 * tree.def (TRUTH_NOT_EXPR): Improve documentation. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 3bd1b81141a..c8a25c4aeed 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 4f59fb86def..8f219cf3247 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 72954bf9e2e..836edc5b3d9 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,18 +3770,94 @@ (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. ;; 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);") @@ -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 4d379928c91..c8cdb1a6692 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 -- 2.30.2