; x87 Floating point
(UNSPEC_FPATAN 65)
(UNSPEC_FYL2X 66)
- (UNSPEC_FSCALE 67)
(UNSPEC_FRNDINT 68)
(UNSPEC_F2XM1 69)
(UNSPEC_TAN_TAN 83)
(UNSPEC_XTRACT_FRACT 84)
(UNSPEC_XTRACT_EXP 85)
+ (UNSPEC_FSCALE_FRACT 86)
+ (UNSPEC_FSCALE_EXP 87)
; REP instruction
(UNSPEC_REP 75)
operands[3] = gen_reg_rtx (XFmode);
})
-(define_insn "*fscale_sfxf3"
- [(set (match_operand:SF 0 "register_operand" "=f")
- (unspec:SF [(match_operand:XF 2 "register_operand" "0")
- (match_operand:XF 1 "register_operand" "u")]
- UNSPEC_FSCALE))
- (clobber (match_scratch:SF 3 "=1"))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && flag_unsafe_math_optimizations"
- "fscale\;fstp\t%y1"
- [(set_attr "type" "fpspc")
- (set_attr "mode" "SF")])
-
-(define_insn "*fscale_dfxf3"
- [(set (match_operand:DF 0 "register_operand" "=f")
- (unspec:DF [(match_operand:XF 2 "register_operand" "0")
- (match_operand:XF 1 "register_operand" "u")]
- UNSPEC_FSCALE))
- (clobber (match_scratch:DF 3 "=1"))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && flag_unsafe_math_optimizations"
- "fscale\;fstp\t%y1"
- [(set_attr "type" "fpspc")
- (set_attr "mode" "DF")])
-
-(define_insn "*fscale_xf3"
- [(set (match_operand:XF 0 "register_operand" "=f")
- (unspec:XF [(match_operand:XF 2 "register_operand" "0")
- (match_operand:XF 1 "register_operand" "u")]
- UNSPEC_FSCALE))
- (clobber (match_scratch:XF 3 "=1"))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && flag_unsafe_math_optimizations"
- "fscale\;fstp\t%y1"
- [(set_attr "type" "fpspc")
- (set_attr "mode" "XF")])
-
(define_insn "*frndintxf2"
[(set (match_operand:XF 0 "register_operand" "=f")
(unspec:XF [(match_operand:XF 1 "register_operand" "0")]
[(set_attr "type" "fpspc")
(set_attr "mode" "XF")])
+(define_insn "*fscalexf4"
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (unspec:XF [(match_operand:XF 2 "register_operand" "0")
+ (match_operand:XF 3 "register_operand" "1")]
+ UNSPEC_FSCALE_FRACT))
+ (set (match_operand:XF 1 "register_operand" "=u")
+ (unspec:XF [(match_dup 2) (match_dup 3)]
+ UNSPEC_FSCALE_EXP))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ && flag_unsafe_math_optimizations"
+ "fscale"
+ [(set_attr "type" "fpspc")
+ (set_attr "mode" "DF")])
+
(define_expand "expsf2"
[(set (match_dup 2)
(float_extend:XF (match_operand:SF 1 "register_operand" "")))
(set (match_dup 6) (minus:XF (match_dup 4) (match_dup 5)))
(set (match_dup 7) (unspec:XF [(match_dup 6)] UNSPEC_F2XM1))
(set (match_dup 9) (plus:XF (match_dup 7) (match_dup 8)))
- (parallel [(set (match_operand:SF 0 "register_operand" "")
- (unspec:SF [(match_dup 9) (match_dup 5)] UNSPEC_FSCALE))
- (clobber (match_scratch:SF 5 ""))])]
+ (parallel [(set (match_dup 10)
+ (unspec:XF [(match_dup 9) (match_dup 5)]
+ UNSPEC_FSCALE_FRACT))
+ (set (match_dup 11)
+ (unspec:XF [(match_dup 9) (match_dup 5)]
+ UNSPEC_FSCALE_EXP))])
+ (set (match_operand:SF 0 "register_operand" "")
+ (float_truncate:SF (match_dup 10)))]
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& flag_unsafe_math_optimizations"
{
rtx temp;
int i;
- for (i=2; i<10; i++)
+ for (i=2; i<12; i++)
operands[i] = gen_reg_rtx (XFmode);
temp = standard_80387_constant_rtx (5); /* fldl2e */
emit_move_insn (operands[3], temp);
(set (match_dup 4) (mult:XF (match_dup 2) (match_dup 3)))
(set (match_dup 5) (unspec:XF [(match_dup 4)] UNSPEC_FRNDINT))
(set (match_dup 6) (minus:XF (match_dup 4) (match_dup 5)))
-
(set (match_dup 7) (unspec:XF [(match_dup 6)] UNSPEC_F2XM1))
(set (match_dup 9) (plus:XF (match_dup 7) (match_dup 8)))
- (parallel [(set (match_operand:DF 0 "register_operand" "")
- (unspec:DF [(match_dup 9) (match_dup 5)] UNSPEC_FSCALE))
- (clobber (match_scratch:DF 5 ""))])]
+ (parallel [(set (match_dup 10)
+ (unspec:XF [(match_dup 9) (match_dup 5)]
+ UNSPEC_FSCALE_FRACT))
+ (set (match_dup 11)
+ (unspec:XF [(match_dup 9) (match_dup 5)]
+ UNSPEC_FSCALE_EXP))])
+ (set (match_operand:DF 0 "register_operand" "")
+ (float_truncate:DF (match_dup 10)))]
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& flag_unsafe_math_optimizations"
{
rtx temp;
int i;
- for (i=2; i<10; i++)
+ for (i=2; i<12; i++)
operands[i] = gen_reg_rtx (XFmode);
temp = standard_80387_constant_rtx (5); /* fldl2e */
emit_move_insn (operands[3], temp);
(set (match_dup 6) (unspec:XF [(match_dup 5)] UNSPEC_F2XM1))
(set (match_dup 8) (plus:XF (match_dup 6) (match_dup 7)))
(parallel [(set (match_operand:XF 0 "register_operand" "")
- (unspec:XF [(match_dup 8) (match_dup 4)] UNSPEC_FSCALE))
- (clobber (match_scratch:XF 5 ""))])]
+ (unspec:XF [(match_dup 8) (match_dup 4)]
+ UNSPEC_FSCALE_FRACT))
+ (set (match_dup 9)
+ (unspec:XF [(match_dup 8) (match_dup 4)]
+ UNSPEC_FSCALE_EXP))])]
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& flag_unsafe_math_optimizations"
{
rtx temp;
int i;
- for (i=2; i<9; i++)
+ for (i=2; i<10; i++)
operands[i] = gen_reg_rtx (XFmode);
temp = standard_80387_constant_rtx (5); /* fldl2e */
emit_move_insn (operands[2], temp);
(set (match_dup 6) (minus:XF (match_dup 4) (match_dup 5)))
(set (match_dup 7) (unspec:XF [(match_dup 6)] UNSPEC_F2XM1))
(set (match_dup 9) (plus:XF (match_dup 7) (match_dup 8)))
- (parallel [(set (match_operand:SF 0 "register_operand" "")
- (unspec:SF [(match_dup 9) (match_dup 5)] UNSPEC_FSCALE))
- (clobber (match_scratch:SF 5 ""))])]
+ (parallel [(set (match_dup 10)
+ (unspec:XF [(match_dup 9) (match_dup 5)]
+ UNSPEC_FSCALE_FRACT))
+ (set (match_dup 11)
+ (unspec:XF [(match_dup 9) (match_dup 5)]
+ UNSPEC_FSCALE_EXP))])
+ (set (match_operand:SF 0 "register_operand" "")
+ (float_truncate:SF (match_dup 10)))]
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& flag_unsafe_math_optimizations"
{
rtx temp;
int i;
- for (i=2; i<10; i++)
+ for (i=2; i<12; i++)
operands[i] = gen_reg_rtx (XFmode);
temp = standard_80387_constant_rtx (6); /* fldl2t */
emit_move_insn (operands[3], temp);
(set (match_dup 6) (minus:XF (match_dup 4) (match_dup 5)))
(set (match_dup 7) (unspec:XF [(match_dup 6)] UNSPEC_F2XM1))
(set (match_dup 9) (plus:XF (match_dup 7) (match_dup 8)))
- (parallel [(set (match_operand:DF 0 "register_operand" "")
- (unspec:DF [(match_dup 9) (match_dup 5)] UNSPEC_FSCALE))
- (clobber (match_scratch:DF 5 ""))])]
+ (parallel [(set (match_dup 10)
+ (unspec:XF [(match_dup 9) (match_dup 5)]
+ UNSPEC_FSCALE_FRACT))
+ (set (match_dup 11)
+ (unspec:XF [(match_dup 9) (match_dup 5)]
+ UNSPEC_FSCALE_EXP))])
+ (set (match_operand:DF 0 "register_operand" "")
+ (float_truncate:DF (match_dup 10)))]
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& flag_unsafe_math_optimizations"
{
rtx temp;
int i;
- for (i=2; i<10; i++)
+ for (i=2; i<12; i++)
operands[i] = gen_reg_rtx (XFmode);
temp = standard_80387_constant_rtx (6); /* fldl2t */
emit_move_insn (operands[3], temp);
(set (match_dup 6) (unspec:XF [(match_dup 5)] UNSPEC_F2XM1))
(set (match_dup 8) (plus:XF (match_dup 6) (match_dup 7)))
(parallel [(set (match_operand:XF 0 "register_operand" "")
- (unspec:XF [(match_dup 8) (match_dup 4)] UNSPEC_FSCALE))
- (clobber (match_scratch:XF 5 ""))])]
+ (unspec:XF [(match_dup 8) (match_dup 4)]
+ UNSPEC_FSCALE_FRACT))
+ (set (match_dup 9)
+ (unspec:XF [(match_dup 8) (match_dup 4)]
+ UNSPEC_FSCALE_EXP))])]
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& flag_unsafe_math_optimizations"
{
rtx temp;
int i;
- for (i=2; i<9; i++)
+ for (i=2; i<10; i++)
operands[i] = gen_reg_rtx (XFmode);
temp = standard_80387_constant_rtx (6); /* fldl2t */
emit_move_insn (operands[2], temp);
(set (match_dup 4) (minus:XF (match_dup 2) (match_dup 3)))
(set (match_dup 5) (unspec:XF [(match_dup 4)] UNSPEC_F2XM1))
(set (match_dup 7) (plus:XF (match_dup 5) (match_dup 6)))
- (parallel [(set (match_operand:SF 0 "register_operand" "")
- (unspec:SF [(match_dup 7) (match_dup 3)] UNSPEC_FSCALE))
- (clobber (match_scratch:SF 3 ""))])]
+ (parallel [(set (match_dup 8)
+ (unspec:XF [(match_dup 7) (match_dup 3)]
+ UNSPEC_FSCALE_FRACT))
+ (set (match_dup 9)
+ (unspec:XF [(match_dup 7) (match_dup 3)]
+ UNSPEC_FSCALE_EXP))])
+ (set (match_operand:SF 0 "register_operand" "")
+ (float_truncate:SF (match_dup 8)))]
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& flag_unsafe_math_optimizations"
{
int i;
- for (i=2; i<8; i++)
+ for (i=2; i<10; i++)
operands[i] = gen_reg_rtx (XFmode);
emit_move_insn (operands[6], CONST1_RTX (XFmode)); /* fld1 */
})
(set (match_dup 4) (minus:XF (match_dup 2) (match_dup 3)))
(set (match_dup 5) (unspec:XF [(match_dup 4)] UNSPEC_F2XM1))
(set (match_dup 7) (plus:XF (match_dup 5) (match_dup 6)))
- (parallel [(set (match_operand:DF 0 "register_operand" "")
- (unspec:DF [(match_dup 7) (match_dup 3)] UNSPEC_FSCALE))
- (clobber (match_scratch:DF 3 ""))])]
+ (parallel [(set (match_dup 8)
+ (unspec:XF [(match_dup 7) (match_dup 3)]
+ UNSPEC_FSCALE_FRACT))
+ (set (match_dup 9)
+ (unspec:XF [(match_dup 7) (match_dup 3)]
+ UNSPEC_FSCALE_EXP))])
+ (set (match_operand:DF 0 "register_operand" "")
+ (float_truncate:DF (match_dup 8)))]
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& flag_unsafe_math_optimizations"
{
int i;
- for (i=2; i<8; i++)
+ for (i=2; i<10; i++)
operands[i] = gen_reg_rtx (XFmode);
emit_move_insn (operands[6], CONST1_RTX (XFmode)); /* fld1 */
})
(set (match_dup 5) (unspec:XF [(match_dup 4)] UNSPEC_F2XM1))
(set (match_dup 7) (plus:XF (match_dup 5) (match_dup 6)))
(parallel [(set (match_operand:XF 0 "register_operand" "")
- (unspec:XF [(match_dup 7) (match_dup 3)] UNSPEC_FSCALE))
- (clobber (match_scratch:XF 3 ""))])]
+ (unspec:XF [(match_dup 7) (match_dup 3)]
+ UNSPEC_FSCALE_FRACT))
+ (set (match_dup 8)
+ (unspec:XF [(match_dup 7) (match_dup 3)]
+ UNSPEC_FSCALE_EXP))])]
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& flag_unsafe_math_optimizations"
{
int i;
- for (i=2; i<8; i++)
+ for (i=2; i<9; i++)
operands[i] = gen_reg_rtx (XFmode);
emit_move_insn (operands[6], CONST1_RTX (XFmode)); /* fld1 */
})
static int get_hard_regnum (stack, rtx);
static rtx emit_pop_insn (rtx, stack, rtx, enum emit_where);
static void emit_swap_insn (rtx, stack, rtx);
+static void swap_to_top(rtx, stack, rtx, rtx);
static bool move_for_stack_reg (rtx, stack, rtx);
static int swap_rtx_condition_1 (rtx);
static int swap_rtx_condition (rtx);
emit_insn_before (swap_rtx, insn);
}
\f
+/* Emit an insns before INSN to swap virtual register SRC1 with
+ the top of stack and virtual register SRC2 with second stack
+ slot. REGSTACK is the stack state before the swaps, and
+ is updated to reflect the swaps. A swap insn is represented as a
+ PARALLEL of two patterns: each pattern moves one reg to the other.
+
+ If SRC1 and/or SRC2 are already at the right place, no swap insn
+ is emitted. */
+
+static void
+swap_to_top (rtx insn, stack regstack, rtx src1, rtx src2)
+{
+ struct stack_def temp_stack;
+ int regno, j, k, temp;
+
+ temp_stack = *regstack;
+
+ /* Place operand 1 at the top of stack. */
+ regno = get_hard_regnum (&temp_stack, src1);
+ if (regno < 0)
+ abort ();
+ if (regno != FIRST_STACK_REG)
+ {
+ k = temp_stack.top - (regno - FIRST_STACK_REG);
+ j = temp_stack.top;
+
+ temp = temp_stack.reg[k];
+ temp_stack.reg[k] = temp_stack.reg[j];
+ temp_stack.reg[j] = temp;
+ }
+
+ /* Place operand 2 next on the stack. */
+ regno = get_hard_regnum (&temp_stack, src2);
+ if (regno < 0)
+ abort ();
+ if (regno != FIRST_STACK_REG + 1)
+ {
+ k = temp_stack.top - (regno - FIRST_STACK_REG);
+ j = temp_stack.top - 1;
+
+ temp = temp_stack.reg[k];
+ temp_stack.reg[k] = temp_stack.reg[j];
+ temp_stack.reg[j] = temp;
+ }
+
+ change_stack (insn, regstack, &temp_stack, EMIT_BEFORE);
+}
+\f
/* Handle a move to or from a stack register in PAT, which is in INSN.
REGSTACK is the current stack. Return whether a control flow insn
was deleted in the process. */
case UNSPEC_FPATAN:
case UNSPEC_FYL2X:
- case UNSPEC_FSCALE:
/* These insns operate on the top two stack slots. */
src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
- {
- struct stack_def temp_stack;
- int regno, j, k, temp;
-
- temp_stack = *regstack;
-
- /* Place operand 1 at the top of stack. */
- regno = get_hard_regnum (&temp_stack, *src1);
- if (regno < 0)
- abort ();
- if (regno != FIRST_STACK_REG)
- {
- k = temp_stack.top - (regno - FIRST_STACK_REG);
- j = temp_stack.top;
-
- temp = temp_stack.reg[k];
- temp_stack.reg[k] = temp_stack.reg[j];
- temp_stack.reg[j] = temp;
- }
-
- /* Place operand 2 next on the stack. */
- regno = get_hard_regnum (&temp_stack, *src2);
- if (regno < 0)
- abort ();
- if (regno != FIRST_STACK_REG + 1)
- {
- k = temp_stack.top - (regno - FIRST_STACK_REG);
- j = temp_stack.top - 1;
-
- temp = temp_stack.reg[k];
- temp_stack.reg[k] = temp_stack.reg[j];
- temp_stack.reg[j] = temp;
- }
-
- change_stack (insn, regstack, &temp_stack, EMIT_BEFORE);
- }
+ swap_to_top (insn, regstack, *src1, *src2);
replace_reg (src1, FIRST_STACK_REG);
replace_reg (src2, FIRST_STACK_REG + 1);
replace_reg (dest, FIRST_STACK_REG);
break;
+ case UNSPEC_FSCALE_FRACT:
+ /* These insns operate on the top two stack slots.
+ first part of double input, double output insn. */
+
+ src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+ src2 = get_true_reg (&XVECEXP (pat_src, 0, 1));
+
+ src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+ src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
+
+ /* Inputs should never die, they are
+ replaced with outputs. */
+ if ((src1_note) || (src2_note))
+ abort();
+
+ swap_to_top (insn, regstack, *src1, *src2);
+
+ /* Push the result back onto stack. Empty stack slot
+ will be filled in second part of insn. */
+ if (STACK_REG_P (*dest)) {
+ regstack->reg[regstack->top] = REGNO (*dest);
+ SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+ replace_reg (dest, FIRST_STACK_REG);
+ }
+
+ replace_reg (src1, FIRST_STACK_REG);
+ replace_reg (src2, FIRST_STACK_REG + 1);
+ break;
+
+ case UNSPEC_FSCALE_EXP:
+ /* These insns operate on the top two stack slots./
+ second part of double input, double output insn. */
+
+ src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+ src2 = get_true_reg (&XVECEXP (pat_src, 0, 1));
+
+ src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+ src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
+
+ /* Inputs should never die, they are
+ replaced with outputs. */
+ if ((src1_note) || (src2_note))
+ abort();
+
+ swap_to_top (insn, regstack, *src1, *src2);
+
+ /* Push the result back onto stack. Fill empty slot from
+ first part of insn and fix top of stack pointer. */
+ if (STACK_REG_P (*dest)) {
+ regstack->reg[regstack->top - 1] = REGNO (*dest);
+ SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+ replace_reg (dest, FIRST_STACK_REG + 1);
+ }
+
+ replace_reg (src1, FIRST_STACK_REG);
+ replace_reg (src2, FIRST_STACK_REG + 1);
+ break;
+
case UNSPEC_SINCOS_COS:
case UNSPEC_TAN_ONE:
case UNSPEC_XTRACT_FRACT: