📄 reg-stack.c
字号:
abort (); } swap_rtx = gen_swapdf (FP_MODE_REG (hard_regno, DFmode), FP_MODE_REG (FIRST_STACK_REG, DFmode)); swap_insn = emit_insn_after (swap_rtx, i1); /* ??? This used to be VOIDmode, but that seems wrong. */ PUT_MODE (swap_insn, QImode);}/* Handle a move to or from a stack register in PAT, which is in INSN. REGSTACK is the current stack. */static voidmove_for_stack_reg (insn, regstack, pat) rtx insn; stack regstack; rtx pat;{ rtx *psrc = get_true_reg (&SET_SRC (pat)); rtx *pdest = get_true_reg (&SET_DEST (pat)); rtx src, dest; rtx note; src = *psrc; dest = *pdest; if (STACK_REG_P (src) && STACK_REG_P (dest)) { /* Write from one stack reg to another. If SRC dies here, then just change the register mapping and delete the insn. */ note = find_regno_note (insn, REG_DEAD, REGNO (src)); if (note) { int i; /* If this is a no-op move, there must not be a REG_DEAD note. */ if (REGNO (src) == REGNO (dest)) abort (); for (i = regstack->top; i >= 0; i--) if (regstack->reg[i] == REGNO (src)) break; /* The source must be live, and the dest must be dead. */ if (i < 0 || get_hard_regnum (regstack, dest) >= FIRST_STACK_REG) abort (); /* It is possible that the dest is unused after this insn. If so, just pop the src. */ if (find_regno_note (insn, REG_UNUSED, REGNO (dest))) { emit_pop_insn (insn, regstack, src, emit_insn_after); delete_insn_for_stacker (insn); return; } regstack->reg[i] = REGNO (dest); SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest)); CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src)); delete_insn_for_stacker (insn); return; } /* The source reg does not die. */ /* If this appears to be a no-op move, delete it, or else it will confuse the machine description output patterns. But if it is REG_UNUSED, we must pop the reg now, as per-insn processing for REG_UNUSED will not work for deleted insns. */ if (REGNO (src) == REGNO (dest)) { if (find_regno_note (insn, REG_UNUSED, REGNO (dest))) emit_pop_insn (insn, regstack, dest, emit_insn_after); delete_insn_for_stacker (insn); return; } /* The destination ought to be dead */ if (get_hard_regnum (regstack, dest) >= FIRST_STACK_REG) abort (); replace_reg (psrc, get_hard_regnum (regstack, src)); regstack->reg[++regstack->top] = REGNO (dest); SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest)); replace_reg (pdest, FIRST_STACK_REG); } else if (STACK_REG_P (src)) { /* Save from a stack reg to MEM, or possibly integer reg. Since only top of stack may be saved, emit an exchange first if needs be. */ emit_swap_insn (insn, regstack, src); note = find_regno_note (insn, REG_DEAD, REGNO (src)); if (note) { replace_reg (&XEXP (note, 0), FIRST_STACK_REG); regstack->top--; CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src)); } else if (GET_MODE (src) == XFmode && regstack->top != REG_STACK_SIZE) { /* A 387 cannot write an XFmode value to a MEM without clobbering the source reg. The output code can handle this by reading back the value from the MEM. But it is more efficient to use a temp register if one is available. Push the source value here if the register stack is not full, and then write the value to memory via a pop. */ rtx push_rtx, push_insn; rtx top_stack_reg = FP_MODE_REG (FIRST_STACK_REG, XFmode); push_rtx = gen_movxf (top_stack_reg, top_stack_reg); push_insn = emit_insn_before (push_rtx, insn); PUT_MODE (push_insn, QImode); REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD, top_stack_reg, REG_NOTES (insn)); } replace_reg (psrc, FIRST_STACK_REG); } else if (STACK_REG_P (dest)) { /* Load from MEM, or possibly integer REG or constant, into the stack regs. The actual target is always the top of the stack. The stack mapping is changed to reflect that DEST is now at top of stack. */ /* The destination ought to be dead */ if (get_hard_regnum (regstack, dest) >= FIRST_STACK_REG) abort (); if (regstack->top >= REG_STACK_SIZE) abort (); regstack->reg[++regstack->top] = REGNO (dest); SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest)); replace_reg (pdest, FIRST_STACK_REG); } else abort ();}voidswap_rtx_condition (pat) rtx pat;{ register char *fmt; register int i; if (GET_RTX_CLASS (GET_CODE (pat)) == '<') { PUT_CODE (pat, swap_condition (GET_CODE (pat))); return; } fmt = GET_RTX_FORMAT (GET_CODE (pat)); for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--) { if (fmt[i] == 'E') { register int j; for (j = XVECLEN (pat, i) - 1; j >= 0; j--) swap_rtx_condition (XVECEXP (pat, i, j)); } else if (fmt[i] == 'e') swap_rtx_condition (XEXP (pat, i)); }}/* Handle a comparison. Special care needs to be taken to avoid causing comparisons that a 387 cannot do correctly, such as EQ. Also, a pop insn may need to be emitted. The 387 does have an `fcompp' insn that can pop two regs, but it is sometimes too expensive to do this - a `fcomp' followed by a `fstpl %st(0)' may be easier to set up. */static voidcompare_for_stack_reg (insn, regstack, pat) rtx insn; stack regstack; rtx pat;{ rtx *src1, *src2; rtx src1_note, src2_note; src1 = get_true_reg (&XEXP (SET_SRC (pat), 0)); src2 = get_true_reg (&XEXP (SET_SRC (pat), 1)); /* ??? If fxch turns out to be cheaper than fstp, give priority to registers that die in this insn - move those to stack top first. */ if (! STACK_REG_P (*src1) || (STACK_REG_P (*src2) && get_hard_regnum (regstack, *src2) == FIRST_STACK_REG)) { rtx temp, next; temp = XEXP (SET_SRC (pat), 0); XEXP (SET_SRC (pat), 0) = XEXP (SET_SRC (pat), 1); XEXP (SET_SRC (pat), 1) = temp; src1 = get_true_reg (&XEXP (SET_SRC (pat), 0)); src2 = get_true_reg (&XEXP (SET_SRC (pat), 1)); next = next_cc0_user (insn); if (next == NULL_RTX) abort (); swap_rtx_condition (PATTERN (next)); INSN_CODE (next) = -1; INSN_CODE (insn) = -1; } /* We will fix any death note later. */ src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1)); if (STACK_REG_P (*src2)) src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2)); else src2_note = NULL_RTX; emit_swap_insn (insn, regstack, *src1); replace_reg (src1, FIRST_STACK_REG); if (STACK_REG_P (*src2)) replace_reg (src2, get_hard_regnum (regstack, *src2)); if (src1_note) { CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (XEXP (src1_note, 0))); replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG); regstack->top--; } /* If the second operand dies, handle that. But if the operands are the same stack register, don't bother, because only one death is needed, and it was just handled. */ if (src2_note && ! (STACK_REG_P (*src1) && STACK_REG_P (*src2) && REGNO (*src1) == REGNO (*src2))) { /* As a special case, two regs may die in this insn if src2 is next to top of stack and the top of stack also dies. Since we have already popped src1, "next to top of stack" is really at top (FIRST_STACK_REG) now. */ if (get_hard_regnum (regstack, XEXP (src2_note, 0)) == FIRST_STACK_REG && src1_note) { CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (XEXP (src2_note, 0))); replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG + 1); regstack->top--; } else { /* The 386 can only represent death of the first operand in the case handled above. In all other cases, emit a separate pop and remove the death note from here. */ link_cc0_insns (insn); remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src2_note, 0))); emit_pop_insn (insn, regstack, XEXP (src2_note, 0), emit_insn_after); } }}/* Substitute new registers in PAT, which is part of INSN. REGSTACK is the current register layout. */static voidsubst_stack_regs_pat (insn, regstack, pat) rtx insn; stack regstack; rtx pat;{ rtx *dest, *src; rtx *src1 = (rtx *) NULL_PTR, *src2; rtx src1_note, src2_note; if (GET_CODE (pat) != SET) return; dest = get_true_reg (&SET_DEST (pat)); src = get_true_reg (&SET_SRC (pat)); /* See if this is a `movM' pattern, and handle elsewhere if so. */ if (*dest != cc0_rtx && (STACK_REG_P (*src) || (STACK_REG_P (*dest) && (GET_CODE (*src) == REG || GET_CODE (*src) == MEM || GET_CODE (*src) == CONST_DOUBLE)))) move_for_stack_reg (insn, regstack, pat); else switch (GET_CODE (SET_SRC (pat))) { case COMPARE: compare_for_stack_reg (insn, regstack, pat); break; case CALL: { int count; for (count = HARD_REGNO_NREGS (REGNO (*dest), GET_MODE (*dest)); --count >= 0;) { regstack->reg[++regstack->top] = REGNO (*dest) + count; SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest) + count); } } replace_reg (dest, FIRST_STACK_REG); break; case REG: /* This is a `tstM2' case. */ if (*dest != cc0_rtx) abort (); src1 = src; /* Fall through. */ case FLOAT_TRUNCATE: case SQRT: case ABS: case NEG: /* These insns only operate on the top of the stack. DEST might be cc0_rtx if we're processing a tstM pattern. Also, it's possible that the tstM case results in a REG_DEAD note on the source. */ if (src1 == 0) src1 = get_true_reg (&XEXP (SET_SRC (pat), 0)); emit_swap_insn (insn, regstack, *src1); src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1)); if (STACK_REG_P (*dest)) replace_reg (dest, FIRST_STACK_REG); if (src1_note) { replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG); regstack->top--; CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1)); } replace_reg (src1, FIRST_STACK_REG); break; case MINUS: case DIV: /* On i386, reversed forms of subM3 and divM3 exist for MODE_FLOAT, so the same code that works for addM3 and mulM3 can be used. */ case MULT: case PLUS: /* These insns can accept the top of stack as a destination from a stack reg or mem, or can use the top of stack as a source and some other stack register (possibly top of stack) as a destination. */ src1 = get_true_reg (&XEXP (SET_SRC (pat), 0)); src2 = get_true_reg (&XEXP (SET_SRC (pat), 1)); /* We will fix any death note later. */ if (STACK_REG_P (*src1)) src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1)); else src1_note = NULL_RTX; if (STACK_REG_P (*src2)) src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2)); else src2_note = NULL_RTX; /* If either operand is not a stack register, then the dest must be top of stack. */ if (! STACK_REG_P (*src1) || ! STACK_REG_P (*src2)) emit_swap_insn (insn, regstack, *dest); else { /* Both operands are REG. If neither operand is already at the top of stack, choose to make the one that is the dest the new top of stack. */ int src1_hard_regnum, src2_hard_regnum; src1_hard_regnum = get_hard_regnum (regstack, *src1); src2_hard_regnum = get_hard_regnum (regstack, *src2); if (src1_hard_regnum == -1 || src2_hard_regnum == -1) abort (); if (src1_hard_regnum != FIRST_STACK_REG && src2_hard_regnum != FIRST_STACK_REG) emit_swap_insn (insn, regstack, *dest); } if (STACK_REG_P (*src1)) replace_reg (src1, get_hard_regnum (regstack, *src1)); if (STACK_REG_P (*src2)) replace_reg (src2, get_hard_regnum (regstack, *src2)); if (src1_note) { /* If the register that dies is at the top of stack, then the destination is somewhere else - merely substitute it. But if the reg that dies is not at top of stack, then move the top of stack to the dead reg, as though we had done the insn and then a store-with-pop. */ if (REGNO (XEXP (src1_note, 0)) == regstack->reg[regstack->top]) { SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest)); replace_reg (dest, get_hard_regnum (regstack, *dest)); } else { int regno = get_hard_regnum (regstack, XEXP (src1_note, 0)); SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest)); replace_reg (dest, regno); regstack->reg[regstack->top - (regno - FIRST_STACK_REG)] = regst
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -