📄 reg-stack.c
字号:
} else if (GET_CODE (pat) == SET && SET_DEST (pat) == pc_rtx && uses_reg_or_mem (SET_SRC (pat))) computed_jump = 1; if (computed_jump) { for (x = label_value_list; x; x = XEXP (x, 1)) record_label_references (insn, gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0))); for (x = forced_labels; x; x = XEXP (x, 1)) record_label_references (insn, gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0))); } record_label_references (insn, pat); } }}/* Return 1 if X contain a REG or MEM that is not in the constant pool. */static intuses_reg_or_mem (x) rtx x;{ enum rtx_code code = GET_CODE (x); int i, j; char *fmt; if (code == REG || (code == MEM && ! (GET_CODE (XEXP (x, 0)) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))))) return 1; fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e' && uses_reg_or_mem (XEXP (x, i))) return 1; if (fmt[i] == 'E') for (j = 0; j < XVECLEN (x, i); j++) if (uses_reg_or_mem (XVECEXP (x, i, j))) return 1; } return 0;}/* If current function returns its result in an fp stack register, return the REG. Otherwise, return 0. */static rtxstack_result (decl) tree decl;{ rtx result = DECL_RTL (DECL_RESULT (decl)); if (result != 0 && ! (GET_CODE (result) == REG && REGNO (result) < FIRST_PSEUDO_REGISTER)) {#ifdef FUNCTION_OUTGOING_VALUE result = FUNCTION_OUTGOING_VALUE (TREE_TYPE (DECL_RESULT (decl)), decl);#else result = FUNCTION_VALUE (TREE_TYPE (DECL_RESULT (decl)), decl);#endif } return result != 0 && STACK_REG_P (result) ? result : 0;}/* Determine the which registers are live at the start of each basic block of the function whose first insn is FIRST. First, if the function returns a real_type, mark the function return type as live at each return point, as the RTL may not give any hint that the register is live. Then, start with the last block and work back to the first block. Similarly, work backwards within each block, insn by insn, recording which regs are dead and which are used (and therefore live) in the hard reg set of block_stack_in[]. After processing each basic block, if there is a label at the start of the block, propagate the live registers to all jumps to this block. As a special case, if there are regs live in this block, that are not live in a block containing a jump to this label, and the block containing the jump has already been processed, we must propagate this block's entry register life back to the block containing the jump, and restart life analysis from there. In the worst case, this function may traverse the insns REG_STACK_SIZE times. This is necessary, since a jump towards the end of the insns may not know that a reg is live at a target that is early in the insns. So we back up and start over with the new reg live. If there are registers that are live at the start of the function, insns are emitted to initialize these registers. Something similar is done after CALL_INSNs in record_reg_life. */static voidstack_reg_life_analysis (first, stackentry) rtx first; HARD_REG_SET *stackentry;{ int reg, block; struct stack_def regstack; { rtx retvalue; if (retvalue = stack_result (current_function_decl)) { /* Find all RETURN insns and mark them. */ for (block = blocks - 1; --block >= 0;) if (GET_CODE (block_end[block]) == JUMP_INSN && GET_CODE (PATTERN (block_end[block])) == RETURN) mark_regs_pat (retvalue, block_out_reg_set+block); /* Mark off the end of last block if we "fall off" the end of the function into the epilogue. */ if (GET_CODE (block_end[blocks-1]) != JUMP_INSN || GET_CODE (PATTERN (block_end[blocks-1])) == RETURN) mark_regs_pat (retvalue, block_out_reg_set+blocks-1); } } /* now scan all blocks backward for stack register use */ block = blocks - 1; while (block >= 0) { register rtx insn, prev; /* current register status at last instruction */ COPY_HARD_REG_SET (regstack.reg_set, block_out_reg_set[block]); prev = block_end[block]; do { insn = prev; prev = PREV_INSN (insn); /* If the insn is a CALL_INSN, we need to ensure that everything dies. But otherwise don't process unless there are some stack regs present. */ if (GET_MODE (insn) == QImode || GET_CODE (insn) == CALL_INSN) record_reg_life (insn, block, ®stack); } while (insn != block_begin[block]); /* Set the state at the start of the block. Mark that no register mapping information known yet. */ COPY_HARD_REG_SET (block_stack_in[block].reg_set, regstack.reg_set); block_stack_in[block].top = -2; /* If there is a label, propagate our register life to all jumps to this label. */ if (GET_CODE (insn) == CODE_LABEL) { register rtx label; int must_restart = 0; for (label = LABEL_REFS (insn); label != insn; label = LABEL_NEXTREF (label)) { int jump_block = BLOCK_NUM (CONTAINING_INSN (label)); if (jump_block < block) IOR_HARD_REG_SET (block_out_reg_set[jump_block], block_stack_in[block].reg_set); else { /* The block containing the jump has already been processed. If there are registers that were not known to be live then, but are live now, we must back up and restart life analysis from that point with the new life information. */ GO_IF_HARD_REG_SUBSET (block_stack_in[block].reg_set, block_out_reg_set[jump_block], 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. */ /* Load zero into each live register. The fact that a register appears live at the function start necessarily implies an error in the user program: it means that (unless the offending code is *never* executed) this program is using uninitialised floating point variables. In order to keep broken code like this happy, we initialise those variables with zero. 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) && ! TEST_HARD_REG_BIT (*stackentry, reg)) { rtx init_rtx; init_rtx = gen_rtx (SET, VOIDmode, FP_MODE_REG(reg, 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); }}/***************************************************************************** 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 (); switch (GET_MODE_CLASS (GET_MODE (*reg))) { default: abort (); case MODE_FLOAT: case MODE_COMPLEX_FLOAT:; } *reg = FP_MODE_REG (regno, 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;}/* 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, DFmode), FP_MODE_REG (FIRST_STACK_REG, DFmode)); pop_insn = (*when) (pop_rtx, insn); /* ??? This used to be VOIDmode, but that seems wrong. */ PUT_MODE (pop_insn, QImode); REG_NOTES (pop_insn) = gen_rtx (EXPR_LIST, REG_DEAD, FP_MODE_REG (FIRST_STACK_REG, 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_swap_insn (insn, regstack, reg) rtx insn; stack regstack; rtx reg;{ int hard_regno; rtx gen_swapdf(); rtx swap_rtx, swap_insn; int tmp, other_reg; /* swap regno temps */ rtx i1; /* the stack-reg insn prior to INSN */ rtx i1set = NULL_RTX; /* the SET rtx within I1 */ hard_regno = get_hard_regnum (regstack, reg); if (hard_regno < FIRST_STACK_REG) abort (); if (hard_regno == FIRST_STACK_REG) return; other_reg = regstack->top - (hard_regno - FIRST_STACK_REG); tmp = regstack->reg[other_reg]; regstack->reg[other_reg] = regstack->reg[regstack->top]; regstack->reg[regstack->top] = tmp; /* Find the previous insn involving stack regs, but don't go past any labels, calls or jumps. */ i1 = prev_nonnote_insn (insn); while (i1 && GET_CODE (i1) == INSN && GET_MODE (i1) != QImode) i1 = prev_nonnote_insn (i1); if (i1) i1set = single_set (i1); if (i1set) { rtx i2; /* the stack-reg insn prior to I1 */ rtx i1src = *get_true_reg (&SET_SRC (i1set)); rtx i1dest = *get_true_reg (&SET_DEST (i1set)); /* If the previous register stack push was from the reg we are to swap with, omit the swap. */ if (GET_CODE (i1dest) == REG && REGNO (i1dest) == FIRST_STACK_REG && GET_CODE (i1src) == REG && REGNO (i1src) == hard_regno - 1 && find_regno_note (i1, REG_DEAD, FIRST_STACK_REG) == NULL_RTX) return; /* If the previous insn wrote to the reg we are to swap with, omit the swap. */ if (GET_CODE (i1dest) == REG && REGNO (i1dest) == hard_regno && GET_CODE (i1src) == REG && REGNO (i1src) == FIRST_STACK_REG && find_regno_note (i1, REG_DEAD, FIRST_STACK_REG) == NULL_RTX) return; } if (GET_RTX_CLASS (GET_CODE (i1)) == 'i' && sets_cc0_p (PATTERN (i1))) { i1 = next_nonnote_insn (i1); if (i1 == insn)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -