📄 reorg.c
字号:
} res->memory = 1; SET_HARD_REG_BIT (res->regs, STACK_POINTER_REGNUM); if (frame_pointer_needed) { SET_HARD_REG_BIT (res->regs, FRAME_POINTER_REGNUM);#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM SET_HARD_REG_BIT (res->regs, HARD_FRAME_POINTER_REGNUM);#endif } for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (global_regs[i]) SET_HARD_REG_BIT (res->regs, i); /* Check for a NOTE_INSN_SETJMP. If it exists, then we must assume that this call can need any register. This is done to be more conservative about how we handle setjmp. We assume that they both use and set all registers. Using all registers ensures that a register will not be considered dead just because it crosses a setjmp call. A register should be considered dead only if the setjmp call returns non-zero. */ if (next && GET_CODE (next) == NOTE && NOTE_LINE_NUMBER (next) == NOTE_INSN_SETJMP) SET_HARD_REG_SET (res->regs); { rtx link; for (link = CALL_INSN_FUNCTION_USAGE (x); link; link = XEXP (link, 1)) if (GET_CODE (XEXP (link, 0)) == USE) { for (i = 1; i < seq_size; i++) { rtx slot_pat = PATTERN (XVECEXP (sequence, 0, i)); if (GET_CODE (slot_pat) == SET && rtx_equal_p (SET_DEST (slot_pat), SET_DEST (XEXP (link, 0)))) break; } if (i >= seq_size) mark_referenced_resources (SET_DEST (XEXP (link, 0)), res, 0); } } } /* ... fall through to other INSN processing ... */ case INSN: case JUMP_INSN:#ifdef INSN_REFERENCES_ARE_DELAYED if (! include_delayed_effects && INSN_REFERENCES_ARE_DELAYED (x)) return;#endif /* No special processing, just speed up. */ mark_referenced_resources (PATTERN (x), res, include_delayed_effects); return; } /* Process each sub-expression and flag what it needs. */ format_ptr = GET_RTX_FORMAT (code); for (i = 0; i < GET_RTX_LENGTH (code); i++) switch (*format_ptr++) { case 'e': mark_referenced_resources (XEXP (x, i), res, include_delayed_effects); break; case 'E': for (j = 0; j < XVECLEN (x, i); j++) mark_referenced_resources (XVECEXP (x, i, j), res, include_delayed_effects); break; }}/* Given X, a part of an insn, and a pointer to a `struct resource', RES, indicate which resources are modified by the insn. If INCLUDE_CALLED_ROUTINE is nonzero, also mark resources potentially set by the called routine. If IN_DEST is nonzero, it means we are inside a SET. Otherwise, objects are being referenced instead of set. We never mark the insn as modifying the condition code unless it explicitly SETs CC0 even though this is not totally correct. The reason for this is that we require a SET of CC0 to immediately precede the reference to CC0. So if some other insn sets CC0 as a side-effect, we know it cannot affect our computation and thus may be placed in a delay slot. */static voidmark_set_resources (x, res, in_dest, include_delayed_effects) register rtx x; register struct resources *res; int in_dest; int include_delayed_effects;{ register enum rtx_code code; register int i, j; register char *format_ptr; restart: code = GET_CODE (x); switch (code) { case NOTE: case BARRIER: case CODE_LABEL: case USE: case CONST_INT: case CONST_DOUBLE: case LABEL_REF: case SYMBOL_REF: case CONST: case PC: /* These don't set any resources. */ return; case CC0: if (in_dest) res->cc = 1; return; case CALL_INSN: /* Called routine modifies the condition code, memory, any registers that aren't saved across calls, global registers and anything explicitly CLOBBERed immediately after the CALL_INSN. */ if (include_delayed_effects) { rtx next = NEXT_INSN (x); rtx prev = PREV_INSN (x); rtx link; res->cc = res->memory = 1; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (call_used_regs[i] || global_regs[i]) SET_HARD_REG_BIT (res->regs, i); /* If X is part of a delay slot sequence, then NEXT should be the first insn after the sequence. */ if (NEXT_INSN (prev) != x) next = NEXT_INSN (NEXT_INSN (prev)); for (link = CALL_INSN_FUNCTION_USAGE (x); link; link = XEXP (link, 1)) if (GET_CODE (XEXP (link, 0)) == CLOBBER) mark_set_resources (SET_DEST (XEXP (link, 0)), res, 1, 0); /* Check for a NOTE_INSN_SETJMP. If it exists, then we must assume that this call can clobber any register. */ if (next && GET_CODE (next) == NOTE && NOTE_LINE_NUMBER (next) == NOTE_INSN_SETJMP) SET_HARD_REG_SET (res->regs); } /* ... and also what it's RTL says it modifies, if anything. */ case JUMP_INSN: case INSN: /* An insn consisting of just a CLOBBER (or USE) is just for flow and doesn't actually do anything, so we ignore it. */#ifdef INSN_SETS_ARE_DELAYED if (! include_delayed_effects && INSN_SETS_ARE_DELAYED (x)) return;#endif x = PATTERN (x); if (GET_CODE (x) != USE && GET_CODE (x) != CLOBBER) goto restart; return; case SET: /* If the source of a SET is a CALL, this is actually done by the called routine. So only include it if we are to include the effects of the calling routine. */ mark_set_resources (SET_DEST (x), res, (include_delayed_effects || GET_CODE (SET_SRC (x)) != CALL), 0); mark_set_resources (SET_SRC (x), res, 0, 0); return; case CLOBBER: mark_set_resources (XEXP (x, 0), res, 1, 0); return; case SEQUENCE: for (i = 0; i < XVECLEN (x, 0); i++) if (! (INSN_ANNULLED_BRANCH_P (XVECEXP (x, 0, 0)) && INSN_FROM_TARGET_P (XVECEXP (x, 0, i)))) mark_set_resources (XVECEXP (x, 0, i), res, 0, include_delayed_effects); return; case POST_INC: case PRE_INC: case POST_DEC: case PRE_DEC: mark_set_resources (XEXP (x, 0), res, 1, 0); return; case ZERO_EXTRACT: mark_set_resources (XEXP (x, 0), res, in_dest, 0); mark_set_resources (XEXP (x, 1), res, 0, 0); mark_set_resources (XEXP (x, 2), res, 0, 0); return; case MEM: if (in_dest) { res->memory = 1; res->unch_memory = RTX_UNCHANGING_P (x); res->volatil = MEM_VOLATILE_P (x); } mark_set_resources (XEXP (x, 0), res, 0, 0); return; case SUBREG: if (in_dest) { if (GET_CODE (SUBREG_REG (x)) != REG) mark_set_resources (SUBREG_REG (x), res, in_dest, include_delayed_effects); else { int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x); int last_regno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); for (i = regno; i < last_regno; i++) SET_HARD_REG_BIT (res->regs, i); } } return; case REG: if (in_dest) for (i = 0; i < HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)); i++) SET_HARD_REG_BIT (res->regs, REGNO (x) + i); return; } /* Process each sub-expression and flag what it needs. */ format_ptr = GET_RTX_FORMAT (code); for (i = 0; i < GET_RTX_LENGTH (code); i++) switch (*format_ptr++) { case 'e': mark_set_resources (XEXP (x, i), res, in_dest, include_delayed_effects); break; case 'E': for (j = 0; j < XVECLEN (x, i); j++) mark_set_resources (XVECEXP (x, i, j), res, in_dest, include_delayed_effects); break; }}/* Return TRUE if this insn should stop the search for insn to fill delay slots. LABELS_P indicates that labels should terminate the search. In all cases, jumps terminate the search. */static intstop_search_p (insn, labels_p) rtx insn; int labels_p;{ if (insn == 0) return 1; switch (GET_CODE (insn)) { case NOTE: case CALL_INSN: return 0; case CODE_LABEL: return labels_p; case JUMP_INSN: case BARRIER: return 1; case INSN: /* OK unless it contains a delay slot or is an `asm' insn of some type. We don't know anything about these. */ return (GET_CODE (PATTERN (insn)) == SEQUENCE || GET_CODE (PATTERN (insn)) == ASM_INPUT || asm_noperands (PATTERN (insn)) >= 0); default: abort (); }}/* Return TRUE if any resources are marked in both RES1 and RES2 or if either resource set contains a volatile memory reference. Otherwise, return FALSE. */static intresource_conflicts_p (res1, res2) struct resources *res1, *res2;{ if ((res1->cc && res2->cc) || (res1->memory && res2->memory) || (res1->unch_memory && res2->unch_memory) || res1->volatil || res2->volatil) return 1;#ifdef HARD_REG_SET return (res1->regs & res2->regs) != HARD_CONST (0);#else { int i; for (i = 0; i < HARD_REG_SET_LONGS; i++) if ((res1->regs[i] & res2->regs[i]) != 0) return 1; return 0; }#endif}/* Return TRUE if any resource marked in RES, a `struct resources', is referenced by INSN. If INCLUDE_CALLED_ROUTINE is set, return if the called routine is using those resources. We compute this by computing all the resources referenced by INSN and seeing if this conflicts with RES. It might be faster to directly check ourselves, and this is the way it used to work, but it means duplicating a large block of complex code. */static intinsn_references_resource_p (insn, res, include_delayed_effects) register rtx insn; register struct resources *res; int include_delayed_effects;{ struct resources insn_res; CLEAR_RESOURCE (&insn_res); mark_referenced_resources (insn, &insn_res, include_delayed_effects); return resource_conflicts_p (&insn_res, res);}/* Return TRUE if INSN modifies resources that are marked in RES. INCLUDE_CALLED_ROUTINE is set if the actions of that routine should be included. CC0 is only modified if it is explicitly set; see comments in front of mark_set_resources for details. */static intinsn_sets_resource_p (insn, res, include_delayed_effects) register rtx insn; register struct resources *res; int include_delayed_effects;{ struct resources insn_sets; CLEAR_RESOURCE (&insn_sets); mark_set_resources (insn, &insn_sets, 0, include_delayed_effects); return resource_conflicts_p (&insn_sets, res);}/* Find a label at the end of the function or before a RETURN. If there is none, make one. */static rtxfind_end_label (){ rtx insn; /* If we found one previously, return it. */ if (end_of_function_label) return end_of_function_label; /* Otherwise, see if there is a label at the end of the function. If there is, it must be that RETURN insns aren't needed, so that is our return label and we don't have to do anything else. */ insn = get_last_insn (); while (GET_CODE (insn) == NOTE || (GET_CODE (insn) == INSN && (GET_CODE (PATTERN (insn)) == USE || GET_CODE (PATTERN (insn)) == CLOBBER))) insn = PREV_INSN (insn); /* When a target threads its epilogue we might already have a suitable return insn. If so put a label before it for the end_of_function_label. */ if (GET_CODE (insn) == BARRIER && GET_CODE (PREV_INSN (insn)) == JUMP_INSN && GET_CODE (PATTERN (PREV_INSN (insn))) == RETURN)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -