📄 function.c
字号:
enum machine_mode promoted_mode, decl_mode; struct function *function = 0; tree context = decl_function_context (decl); /* Get the current rtl used for this object and it's original mode. */ reg = TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl) : DECL_RTL (decl); /* No need to do anything if decl has no rtx yet since in that case caller is setting TREE_ADDRESSABLE and a stack slot will be assigned when the rtl is made. */ if (reg == 0) return; /* Get the declared mode for this object. */ decl_mode = (TREE_CODE (decl) == SAVE_EXPR ? TYPE_MODE (TREE_TYPE (decl)) : DECL_MODE (decl)); /* Get the mode it's actually stored in. */ promoted_mode = GET_MODE (reg); /* If this variable comes from an outer function, find that function's saved context. */ if (context != current_function_decl) for (function = outer_function_chain; function; function = function->next) if (function->decl == context) break; /* If this is a variable-size object with a pseudo to address it, put that pseudo into the stack, if the var is nonlocal. */ if (DECL_NONLOCAL (decl) && GET_CODE (reg) == MEM && GET_CODE (XEXP (reg, 0)) == REG && REGNO (XEXP (reg, 0)) > LAST_VIRTUAL_REGISTER) { reg = XEXP (reg, 0); decl_mode = promoted_mode = GET_MODE (reg); } if (GET_CODE (reg) != REG) return; if (function) { if (REGNO (reg) < function->max_parm_reg) new = function->parm_reg_stack_loc[REGNO (reg)]; if (new == 0) new = assign_outer_stack_local (GET_MODE (reg), GET_MODE_SIZE (decl_mode), 0, function); } else { if (REGNO (reg) < max_parm_reg) new = parm_reg_stack_loc[REGNO (reg)]; if (new == 0) new = assign_stack_local (GET_MODE (reg), GET_MODE_SIZE (decl_mode), 0); } XEXP (reg, 0) = XEXP (new, 0); /* `volatil' bit means one thing for MEMs, another entirely for REGs. */ REG_USERVAR_P (reg) = 0; PUT_CODE (reg, MEM); PUT_MODE (reg, decl_mode); /* If this is a memory ref that contains aggregate components, mark it as such for cse and loop optimize. */ MEM_IN_STRUCT_P (reg) = (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE); /* Now make sure that all refs to the variable, previously made when it was a register, are fixed up to be valid again. */ if (function) { struct var_refs_queue *temp; /* Variable is inherited; fix it up when we get back to its function. */ push_obstacks (function->function_obstack, function->function_maybepermanent_obstack); temp = (struct var_refs_queue *) oballoc (sizeof (struct var_refs_queue)); temp->modified = reg; temp->promoted_mode = promoted_mode; temp->unsignedp = TREE_UNSIGNED (TREE_TYPE (decl)); temp->next = function->fixup_var_refs_queue; function->fixup_var_refs_queue = temp; pop_obstacks (); } else /* Variable is local; fix it up now. */ fixup_var_refs (reg, promoted_mode, TREE_UNSIGNED (TREE_TYPE (decl)));}static voidfixup_var_refs (var, promoted_mode, unsignedp) rtx var; enum machine_mode promoted_mode; int unsignedp;{ tree pending; rtx first_insn = get_insns (); struct sequence_stack *stack = sequence_stack; tree rtl_exps = rtl_expr_chain; /* Must scan all insns for stack-refs that exceed the limit. */ fixup_var_refs_insns (var, promoted_mode, unsignedp, first_insn, stack == 0); /* Scan all pending sequences too. */ for (; stack; stack = stack->next) { push_to_sequence (stack->first); fixup_var_refs_insns (var, promoted_mode, unsignedp, stack->first, stack->next != 0); /* Update remembered end of sequence in case we added an insn at the end. */ stack->last = get_last_insn (); end_sequence (); } /* Scan all waiting RTL_EXPRs too. */ for (pending = rtl_exps; pending; pending = TREE_CHAIN (pending)) { rtx seq = RTL_EXPR_SEQUENCE (TREE_VALUE (pending)); if (seq != const0_rtx && seq != 0) { push_to_sequence (seq); fixup_var_refs_insns (var, promoted_mode, unsignedp, seq, 0); end_sequence (); } }}/* This structure is used by the following two functions to record MEMs or pseudos used to replace VAR, any SUBREGs of VAR, and any MEMs containing VAR as an address. We need to maintain this list in case two operands of an insn were required to match; in that case we must ensure we use the same replacement. */struct fixup_replacement{ rtx old; rtx new; struct fixup_replacement *next;}; /* REPLACEMENTS is a pointer to a list of the above structures and X is some part of an insn. Return a struct fixup_replacement whose OLD value is equal to X. Allocate a new structure if no such entry exists. */static struct fixup_replacement *find_fixup_replacement (replacements, x) struct fixup_replacement **replacements; rtx x;{ struct fixup_replacement *p; /* See if we have already replaced this. */ for (p = *replacements; p && p->old != x; p = p->next) ; if (p == 0) { p = (struct fixup_replacement *) oballoc (sizeof (struct fixup_replacement)); p->old = x; p->new = 0; p->next = *replacements; *replacements = p; } return p;}/* Scan the insn-chain starting with INSN for refs to VAR and fix them up. TOPLEVEL is nonzero if this chain is the main chain of insns for the current function. */static voidfixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel) rtx var; enum machine_mode promoted_mode; int unsignedp; rtx insn; int toplevel;{ while (insn) { rtx next = NEXT_INSN (insn); rtx note; if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) { /* The insn to load VAR from a home in the arglist is now a no-op. When we see it, just delete it. */ if (toplevel && GET_CODE (PATTERN (insn)) == SET && SET_DEST (PATTERN (insn)) == var && rtx_equal_p (SET_SRC (PATTERN (insn)), var)) { /* In unoptimized compilation, we shouldn't call delete_insn except in jump.c doing warnings. */ PUT_CODE (insn, NOTE); NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; NOTE_SOURCE_FILE (insn) = 0; if (insn == last_parm_insn) last_parm_insn = PREV_INSN (next); } else { /* See if we have to do anything to INSN now that VAR is in memory. If it needs to be loaded into a pseudo, use a single pseudo for the entire insn in case there is a MATCH_DUP between two operands. We pass a pointer to the head of a list of struct fixup_replacements. If fixup_var_refs_1 needs to allocate pseudos or replacement MEMs (for SUBREGs), it will record them in this list. If it allocated a pseudo for any replacement, we copy into it here. */ struct fixup_replacement *replacements = 0; fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn, &replacements); while (replacements) { if (GET_CODE (replacements->new) == REG) { rtx insert_before; rtx seq; /* OLD might be a (subreg (mem)). */ if (GET_CODE (replacements->old) == SUBREG) replacements->old = fixup_memory_subreg (replacements->old, insn, 0); else replacements->old = fixup_stack_1 (replacements->old, insn); /* We can not separate USE insns from the CALL_INSN that they belong to. If this is a CALL_INSN, insert the move insn before the USE insns preceding it instead of immediately before the insn. */ if (GET_CODE (insn) == CALL_INSN) { insert_before = insn; while (GET_CODE (PREV_INSN (insert_before)) == INSN && GET_CODE (PATTERN (PREV_INSN (insert_before))) == USE) insert_before = PREV_INSN (insert_before); } else insert_before = insn; /* If we are changing the mode, do a conversion. This might be wasteful, but combine.c will eliminate much of the waste. */ if (GET_MODE (replacements->new) != GET_MODE (replacements->old)) { start_sequence (); convert_move (replacements->new, replacements->old, unsignedp); seq = gen_sequence (); end_sequence (); } else seq = gen_move_insn (replacements->new, replacements->old); emit_insn_before (seq, insert_before); } replacements = replacements->next; } } /* Also fix up any invalid exprs in the REG_NOTES of this insn. But don't touch other insns referred to by reg-notes; we will get them elsewhere. */ for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) if (GET_CODE (note) != INSN_LIST) XEXP (note, 0) = walk_fixup_memory_subreg (XEXP (note, 0), insn); } insn = next; }}/* VAR is a MEM that used to be a pseudo register with mode PROMOTED_MODE. See if the rtx expression at *LOC in INSN needs to be changed. REPLACEMENTS is a pointer to a list head that starts out zero, but may contain a list of original rtx's and replacements. If we find that we need to modify this insn by replacing a memory reference with a pseudo or by making a new MEM to implement a SUBREG, we consult that list to see if we have already chosen a replacement. If none has already been allocated, we allocate it and update the list. fixup_var_refs_insns will copy VAR or the SUBREG, as appropriate, to the pseudo. */static voidfixup_var_refs_1 (var, promoted_mode, loc, insn, replacements) register rtx var; enum machine_mode promoted_mode; register rtx *loc; rtx insn; struct fixup_replacement **replacements;{ register int i; register rtx x = *loc; RTX_CODE code = GET_CODE (x); register char *fmt; register rtx tem, tem1; struct fixup_replacement *replacement; switch (code) { case MEM: if (var == x) { /* If we already have a replacement, use it. Otherwise, try to fix up this address in case it is invalid. */ replacement = find_fixup_replacement (replacements, var); if (replacement->new) { *loc = replacement->new; return; } *loc = replacement->new = x = fixup_stack_1 (x, insn); /* Unless we are forcing memory to register or we changed the mode, we can leave things the way they are if the insn is valid. */ INSN_CODE (insn) = -1; if (! flag_force_mem && GET_MODE (x) == promoted_mode && recog_memoized (insn) >= 0) return; *loc = replacement->new = gen_reg_rtx (promoted_mode); return; } /* If X contains VAR, we need to unshare it here so that we update each occurrence separately. But all identical MEMs in one insn must be replaced with the same rtx because of the possibility of MATCH_DUPs. */ if (reg_mentioned_p (var, x)) { replacement = find_fixup_replacement (replacements, x); if (replacement->new == 0) replacement->new = copy_most_rtx (x, var); *loc = x = replacement->new; } break; case REG: case CC0: case PC: case CONST_INT: case CONST: case SYMBOL_REF: case LABEL_REF: case CONST_DOUBLE: return; case SIGN_EXTRACT: case ZERO_EXTRACT: /* Note that in some cases those types of expressions are altered by optimize_bit_field, and do not survive to get here. */ if (XEXP (x, 0) == var || (GET_CODE (XEXP (x, 0)) == SUBREG && SUBREG_REG (XEXP (x, 0)) == var)) { /* Get TEM as a valid MEM in the mode presently in the insn. We don't worry about the possibility of MATCH_DUP here; it is highly unlikely and would be tricky to handle. */ tem = XEXP (x, 0); if (GET_CODE (tem) == SUBREG) tem = fixup_memory_subreg (tem, insn, 1); tem = fixup_stack_1 (tem, insn); /* Unless we want to load from memory, get TEM into the proper mode for an extract from memory. This can only be done if the extract is at a constant position and length. */ if (! flag_force_mem && GET_CODE (XEXP (x, 1)) == CONST_INT && GET_CODE (XEXP (x, 2)) == CONST_INT && ! mode_dependent_address_p (XEXP (tem, 0)) && ! MEM_VOLATILE_P (tem)) { enum machine_mode wanted_mode = VOIDmode; enum machine_mode is_mode = GET_MODE (tem); int width = INTVAL (XEXP (x, 1)); int pos = INTVAL (XEXP (x, 2));#ifdef HAVE_extzv if (GET_CODE (x) == ZERO_EXTRACT) wanted_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];#endif#ifdef HAVE_extv if (GET_CODE (x) == SIGN_EXTRACT) wanted_mode = insn_operand_mode[(int) CODE_FOR_extv][1];#endif /* If we have a narrower mode, we can do something. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -