diff options
Diffstat (limited to 'gcc/reg-stack.c')
-rw-r--r-- | gcc/reg-stack.c | 145 |
1 files changed, 108 insertions, 37 deletions
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index c3279d0206f..2836e63d7ed 100644 --- a/gcc/reg-stack.c +++ b/gcc/reg-stack.c @@ -249,6 +249,7 @@ static void remove_regno_note (rtx, enum reg_note, unsigned int); 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); @@ -1034,6 +1035,54 @@ emit_swap_insn (rtx insn, stack regstack, rtx reg) emit_insn_before (swap_rtx, insn); } +/* 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); +} + /* 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. */ @@ -1701,7 +1750,6 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat) 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)); @@ -1710,42 +1758,7 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat) 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); @@ -1768,6 +1781,64 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat) 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: |