📄 reg-stack.c
字号:
win); IOR_HARD_REG_SET (block_out_reg_set[jump_block], block_stack_in[block].reg_set); block = jump_block; must_restart = 1; win: ; } } if (must_restart) continue; } if (block_drops_in[block]) IOR_HARD_REG_SET (block_out_reg_set[block-1], block_stack_in[block].reg_set); block -= 1; } { /* If any reg is live at the start of the first block of a function, then we must guarantee that the reg holds some value by generating our own "load" of that register. Otherwise a 387 would fault trying to access an empty register. */ HARD_REG_SET empty_regs; CLEAR_HARD_REG_SET (empty_regs); GO_IF_HARD_REG_SUBSET (block_stack_in[0].reg_set, empty_regs, no_live_regs); } /* Load zero into each live register. The fact that a register appears live at the function start does not necessarily imply an error in the user program: it merely means that we could not determine that there wasn't such an error, just as -Wunused sometimes gives "incorrect" warnings. In those cases, these initializations will do no harm. Note that we are inserting virtual register references here: these insns must be processed by convert_regs later. Also, these insns will not be in block_number, so BLOCK_NUM() will fail for them. */ for (reg = LAST_STACK_REG; reg >= FIRST_STACK_REG; reg--) if (TEST_HARD_REG_BIT (block_stack_in[0].reg_set, reg)) { rtx init_rtx; init_rtx = gen_rtx (SET, VOIDmode, FP_mode_reg[reg][(int) DFmode], CONST0_RTX (DFmode)); block_begin[0] = emit_insn_after (init_rtx, first); PUT_MODE (block_begin[0], QImode); CLEAR_HARD_REG_BIT (block_stack_in[0].reg_set, reg); } no_live_regs: ;}/***************************************************************************** This section deals with stack register substitution, and forms the second pass over the RTL. *****************************************************************************//* Replace REG, which is a pointer to a stack reg RTX, with an RTX for the desired hard REGNO. */static voidreplace_reg (reg, regno) rtx *reg; int regno;{ if (regno < FIRST_STACK_REG || regno > LAST_STACK_REG || ! STACK_REG_P (*reg)) abort (); if (GET_MODE_CLASS (GET_MODE (*reg)) != MODE_FLOAT) abort (); *reg = FP_mode_reg[regno][(int) GET_MODE (*reg)];}/* Remove a note of type NOTE, which must be found, for register number REGNO from INSN. Remove only one such note. */static voidremove_regno_note (insn, note, regno) rtx insn; enum reg_note note; int regno;{ register rtx *note_link, this; note_link = ®_NOTES(insn); for (this = *note_link; this; this = XEXP (this, 1)) if (REG_NOTE_KIND (this) == note && REG_P (XEXP (this, 0)) && REGNO (XEXP (this, 0)) == regno) { *note_link = XEXP (this, 1); return; } else note_link = &XEXP (this, 1); abort ();}/* Find the hard register number of virtual register REG in REGSTACK. The hard register number is relative to the top of the stack. -1 is returned if the register is not found. */static intget_hard_regnum (regstack, reg) stack regstack; rtx reg;{ int i; if (! STACK_REG_P (reg)) abort (); for (i = regstack->top; i >= 0; i--) if (regstack->reg[i] == REGNO (reg)) break; return i >= 0 ? (FIRST_STACK_REG + regstack->top - i) : -1;}/* Delete INSN from the RTL. Mark the insn, but don't remove it from the chain of insns. Doing so could confuse block_begin and block_end if this were the only insn in the block. */static voiddelete_insn_for_stacker (insn) rtx insn;{ PUT_CODE (insn, NOTE); NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; NOTE_SOURCE_FILE (insn) = 0; INSN_DELETED_P (insn) = 1;}/* Emit an insn to pop virtual register REG before or after INSN. REGSTACK is the stack state after INSN and is updated to reflect this pop. WHEN is either emit_insn_before or emit_insn_after. A pop insn is represented as a SET whose destination is the register to be popped and source is the top of stack. A death note for the top of stack cases the movdf pattern to pop. */static rtxemit_pop_insn (insn, regstack, reg, when) rtx insn; stack regstack; rtx reg; rtx (*when)();{ rtx pop_insn, pop_rtx; int hard_regno; hard_regno = get_hard_regnum (regstack, reg); if (hard_regno < FIRST_STACK_REG) abort (); pop_rtx = gen_rtx (SET, VOIDmode, FP_mode_reg[hard_regno][(int) DFmode], FP_mode_reg[FIRST_STACK_REG][(int) DFmode]); pop_insn = (*when) (pop_rtx, insn); PUT_MODE (pop_insn, VOIDmode); REG_NOTES (pop_insn) = gen_rtx (EXPR_LIST, REG_DEAD, FP_mode_reg[FIRST_STACK_REG][(int) DFmode], REG_NOTES (pop_insn)); regstack->reg[regstack->top - (hard_regno - FIRST_STACK_REG)] = regstack->reg[regstack->top]; regstack->top -= 1; CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (reg)); return pop_insn;}/* Emit an insn before or after INSN to swap virtual register REG with the top of stack. WHEN should be `emit_insn_before' or `emit_insn_before' REGSTACK is the stack state before the swap, and is updated to reflect the swap. A swap insn is represented as a PARALLEL of two patterns: each pattern moves one reg to the other. If REG is already at the top of the stack, no insn is emitted. */static voidemit_hard_swap_insn (insn, regstack, hard_regno, when) rtx insn; stack regstack; int hard_regno; rtx (*when)();{ rtx gen_swapdf(); rtx swap_rtx, swap_insn; int tmp, other; if (hard_regno == FIRST_STACK_REG) return; swap_rtx = gen_swapdf (FP_mode_reg[hard_regno][(int) DFmode], FP_mode_reg[FIRST_STACK_REG][(int) DFmode]); swap_insn = (*when) (swap_rtx, insn); PUT_MODE (swap_insn, VOIDmode); other = regstack->top - (hard_regno - FIRST_STACK_REG); tmp = regstack->reg[other]; regstack->reg[other] = regstack->reg[regstack->top]; regstack->reg[regstack->top] = tmp;}/* Emit an insn before or after INSN to swap virtual register REG with the top of stack. See comments before emit_hard_swap_insn. */static voidemit_swap_insn (insn, regstack, reg, when) rtx insn; stack regstack; rtx reg; rtx (*when)();{ int hard_regno; hard_regno = get_hard_regnum (regstack, reg); if (hard_regno < FIRST_STACK_REG) abort (); emit_hard_swap_insn (insn, regstack, hard_regno, when);}/* 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 *src = get_true_reg (&SET_SRC (pat)); rtx *dest = get_true_reg (&SET_DEST (pat)); rtx note; 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 (src, get_hard_regnum (regstack, *src)); regstack->reg[++regstack->top] = REGNO (*dest); SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest)); replace_reg (dest, 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, emit_insn_before); 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)); } replace_reg (src, 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 (dest, FIRST_STACK_REG); } else abort ();}/* 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)); /* The first argument must always be a stack reg. */ /* ??? why? */ if (! STACK_REG_P (*src1)) abort (); /* 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 = 0; emit_swap_insn (insn, regstack, *src1, emit_insn_before); 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); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -