From: Richard Henderson Date: Sat, 30 Apr 2005 03:17:53 +0000 (-0700) Subject: function.c (instantiate_decls): Remove valid_only argument. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=bbf9b9139b111d41be207d2925b619828b1c081b;p=gcc.git function.c (instantiate_decls): Remove valid_only argument. * function.c (instantiate_decls): Remove valid_only argument. (instantiate_decls_1, instantiate_decl): Likewise. (instantiate_virtual_regs_1): Delete. (instantiate_virtual_regs_lossage): Delete. (instantiate_virtual_regs_in_rtx): New. (safe_insn_predicate): New. (instantiate_virtual_regs_in_insn): New. (instantiate_virtual_regs): Update to match all that. Only run instantiate_decls once. From-SVN: r99032 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4c5843aba37..7b5c62c85fe 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2005-04-29 Richard Henderson + + * function.c (instantiate_decls): Remove valid_only argument. + (instantiate_decls_1, instantiate_decl): Likewise. + (instantiate_virtual_regs_1): Delete. + (instantiate_virtual_regs_lossage): Delete. + (instantiate_virtual_regs_in_rtx): New. + (safe_insn_predicate): New. + (instantiate_virtual_regs_in_insn): New. + (instantiate_virtual_regs): Update to match all that. Only run + instantiate_decls once. + 2005-04-29 Richard Henderson Daniel Jacobowitz diff --git a/gcc/function.c b/gcc/function.c index a092d6c62e0..156dc3bca71 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -189,11 +189,6 @@ struct temp_slot GTY(()) static rtx assign_stack_local_1 (enum machine_mode, HOST_WIDE_INT, int, struct function *); static struct temp_slot *find_temp_slot_from_address (rtx); -static void instantiate_decls (tree, int); -static void instantiate_decls_1 (tree, int); -static void instantiate_decl (rtx, HOST_WIDE_INT, int); -static rtx instantiate_new_reg (rtx, HOST_WIDE_INT *); -static int instantiate_virtual_regs_1 (rtx *, rtx, int); static void pad_to_arg_alignment (struct args_size *, int, struct args_size *); static void pad_below (struct args_size *, enum machine_mode, tree); static void reorder_blocks_1 (rtx, tree, varray_type *); @@ -214,7 +209,6 @@ static rtx keep_stack_depressed (rtx); static void prepare_function_start (tree); static void do_clobber_return_reg (rtx, void *); static void do_use_return_reg (rtx, void *); -static void instantiate_virtual_regs_lossage (rtx); static void set_insn_locators (rtx, int) ATTRIBUTE_UNUSED; /* Pointer to chain of `struct function' for containing functions. */ @@ -1217,608 +1211,446 @@ static int cfa_offset; #endif -/* Pass through the INSNS of function FNDECL and convert virtual register - references to hard register references. */ +/* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX + is a virtual register, return the equivalent hard register and set the + offset indirectly through the pointer. Otherwise, return 0. */ -void -instantiate_virtual_regs (void) +static rtx +instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset) { - rtx insn; - - /* Compute the offsets to use for this function. */ - in_arg_offset = FIRST_PARM_OFFSET (current_function_decl); - var_offset = STARTING_FRAME_OFFSET; - dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl); - out_arg_offset = STACK_POINTER_OFFSET; - cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl); - - /* Scan all variables and parameters of this function. For each that is - in memory, instantiate all virtual registers if the result is a valid - address. If not, we do it later. That will handle most uses of virtual - regs on many machines. */ - instantiate_decls (current_function_decl, 1); - - /* Initialize recognition, indicating that volatile is OK. */ - init_recog (); - - /* Scan through all the insns, instantiating every virtual register still - present. */ - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - { - instantiate_virtual_regs_1 (&PATTERN (insn), insn, 1); - if (INSN_DELETED_P (insn)) - continue; - instantiate_virtual_regs_1 (®_NOTES (insn), NULL_RTX, 0); - /* Instantiate any virtual registers in CALL_INSN_FUNCTION_USAGE. */ - if (CALL_P (insn)) - instantiate_virtual_regs_1 (&CALL_INSN_FUNCTION_USAGE (insn), - NULL_RTX, 0); - - /* Past this point all ASM statements should match. Verify that - to avoid failures later in the compilation process. */ - if (asm_noperands (PATTERN (insn)) >= 0 - && ! check_asm_operands (PATTERN (insn))) - instantiate_virtual_regs_lossage (insn); - } + rtx new; + HOST_WIDE_INT offset; - /* Now instantiate the remaining register equivalences for debugging info. - These will not be valid addresses. */ - instantiate_decls (current_function_decl, 0); + if (x == virtual_incoming_args_rtx) + new = arg_pointer_rtx, offset = in_arg_offset; + else if (x == virtual_stack_vars_rtx) + new = frame_pointer_rtx, offset = var_offset; + else if (x == virtual_stack_dynamic_rtx) + new = stack_pointer_rtx, offset = dynamic_offset; + else if (x == virtual_outgoing_args_rtx) + new = stack_pointer_rtx, offset = out_arg_offset; + else if (x == virtual_cfa_rtx) + new = arg_pointer_rtx, offset = cfa_offset; + else + return NULL_RTX; - /* Indicate that, from now on, assign_stack_local should use - frame_pointer_rtx. */ - virtuals_instantiated = 1; + *poffset = offset; + return new; } -/* Scan all decls in FNDECL (both variables and parameters) and instantiate - all virtual registers in their DECL_RTL's. +/* A subroutine of instantiate_virtual_regs, called via for_each_rtx. + Instantiate any virtual registers present inside of *LOC. The expression + is simplified, as much as possible, but is not to be considered "valid" + in any sense implied by the target. If any change is made, set CHANGED + to true. */ - If VALID_ONLY, do this only if the resulting address is still valid. - Otherwise, always do it. */ - -static void -instantiate_decls (tree fndecl, int valid_only) +static int +instantiate_virtual_regs_in_rtx (rtx *loc, void *data) { - tree decl; + HOST_WIDE_INT offset; + bool *changed = (bool *) data; + rtx x, new; - /* Process all parameters of the function. */ - for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl)) + x = *loc; + if (x == 0) + return 0; + + switch (GET_CODE (x)) { - HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl)); - HOST_WIDE_INT size_rtl; + case REG: + new = instantiate_new_reg (x, &offset); + if (new) + { + *loc = plus_constant (new, offset); + if (changed) + *changed = true; + } + return -1; + + case PLUS: + new = instantiate_new_reg (XEXP (x, 0), &offset); + if (new) + { + new = plus_constant (new, offset); + *loc = simplify_gen_binary (PLUS, GET_MODE (x), new, XEXP (x, 1)); + if (changed) + *changed = true; + return -1; + } - instantiate_decl (DECL_RTL (decl), size, valid_only); + /* FIXME -- from old code */ + /* If we have (plus (subreg (virtual-reg)) (const_int)), we know + we can commute the PLUS and SUBREG because pointers into the + frame are well-behaved. */ + break; - /* If the parameter was promoted, then the incoming RTL mode may be - larger than the declared type size. We must use the larger of - the two sizes. */ - size_rtl = GET_MODE_SIZE (GET_MODE (DECL_INCOMING_RTL (decl))); - size = MAX (size_rtl, size); - instantiate_decl (DECL_INCOMING_RTL (decl), size, valid_only); + default: + break; } - /* Now process all variables defined in the function or its subblocks. */ - instantiate_decls_1 (DECL_INITIAL (fndecl), valid_only); + return 0; } -/* Subroutine of instantiate_decls: Process all decls in the given - BLOCK node and all its subblocks. */ +/* A subroutine of instantiate_virtual_regs_in_insn. Return true if X + matches the predicate for insn CODE operand OPERAND. */ -static void -instantiate_decls_1 (tree let, int valid_only) +static int +safe_insn_predicate (int code, int operand, rtx x) { - tree t; + const struct insn_operand_data *op_data; - for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t)) - if (DECL_RTL_SET_P (t)) - instantiate_decl (DECL_RTL (t), - int_size_in_bytes (TREE_TYPE (t)), - valid_only); + if (code < 0) + return true; - /* Process all subblocks. */ - for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t)) - instantiate_decls_1 (t, valid_only); -} + op_data = &insn_data[code].operand[operand]; + if (op_data->predicate == NULL) + return true; -/* Subroutine of the preceding procedures: Given RTL representing a - decl and the size of the object, do any instantiation required. + return op_data->predicate (x, op_data->mode); +} - If VALID_ONLY is nonzero, it means that the RTL should only be - changed if the new address is valid. */ +/* A subroutine of instantiate_virtual_regs. Instantiate any virtual + registers present inside of insn. The result will be a valid insn. */ static void -instantiate_decl (rtx x, HOST_WIDE_INT size, int valid_only) +instantiate_virtual_regs_in_insn (rtx insn) { - enum machine_mode mode; - rtx addr; - - if (x == 0) - return; + HOST_WIDE_INT offset; + int insn_code, i; + bool any_change; + rtx set, new, x, seq; - /* If this is a CONCAT, recurse for the pieces. */ - if (GET_CODE (x) == CONCAT) + /* There are some special cases to be handled first. */ + set = single_set (insn); + if (set) { - instantiate_decl (XEXP (x, 0), size / 2, valid_only); - instantiate_decl (XEXP (x, 1), size / 2, valid_only); - return; - } - - /* If this is not a MEM, no need to do anything. Similarly if the - address is a constant or a register that is not a virtual register. */ - if (!MEM_P (x)) - return; + /* We're allowed to assign to a virtual register. This is interpreted + to mean that the underlying register gets assigned the inverse + transformation. This is used, for example, in the handling of + non-local gotos. */ + new = instantiate_new_reg (SET_DEST (set), &offset); + if (new) + { + start_sequence (); - addr = XEXP (x, 0); - if (CONSTANT_P (addr) - || (REG_P (addr) - && (REGNO (addr) < FIRST_VIRTUAL_REGISTER - || REGNO (addr) > LAST_VIRTUAL_REGISTER))) - return; + for_each_rtx (&SET_SRC (set), instantiate_virtual_regs_in_rtx, NULL); + x = simplify_gen_binary (PLUS, GET_MODE (new), SET_SRC (set), + GEN_INT (-offset)); + x = force_operand (x, new); + if (x != new) + emit_move_insn (new, x); - /* If we should only do this if the address is valid, copy the address. - We need to do this so we can undo any changes that might make the - address invalid. This copy is unfortunate, but probably can't be - avoided. */ + seq = get_insns (); + end_sequence (); - if (valid_only) - addr = copy_rtx (addr); + emit_insn_before (seq, insn); + delete_insn (insn); + return; + } - instantiate_virtual_regs_1 (&addr, NULL_RTX, 0); + /* Handle a straight copy from a virtual register by generating a + new add insn. The difference between this and falling through + to the generic case is avoiding a new pseudo and eliminating a + move insn in the initial rtl stream. */ + new = instantiate_new_reg (SET_SRC (set), &offset); + if (new && offset != 0 + && REG_P (SET_DEST (set)) + && REGNO (SET_DEST (set)) > LAST_VIRTUAL_REGISTER) + { + start_sequence (); - if (valid_only && size >= 0) - { - unsigned HOST_WIDE_INT decl_size = size; + x = expand_simple_binop (GET_MODE (SET_DEST (set)), PLUS, + new, GEN_INT (offset), SET_DEST (set), + 1, OPTAB_LIB_WIDEN); + if (x != SET_DEST (set)) + emit_move_insn (SET_DEST (set), x); - /* Now verify that the resulting address is valid for every integer or - floating-point mode up to and including SIZE bytes long. We do this - since the object might be accessed in any mode and frame addresses - are shared. */ + seq = get_insns (); + end_sequence (); - for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); - mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size; - mode = GET_MODE_WIDER_MODE (mode)) - if (! memory_address_p (mode, addr)) + emit_insn_before (seq, insn); + delete_insn (insn); return; + } - for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); - mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size; - mode = GET_MODE_WIDER_MODE (mode)) - if (! memory_address_p (mode, addr)) - return; - } + extract_insn (insn); - /* Put back the address now that we have updated it and we either know - it is valid or we don't care whether it is valid. */ + /* Handle a plus involving a virtual register by determining if the + operands remain valid if they're modified in place. */ + if (GET_CODE (SET_SRC (set)) == PLUS + && recog_data.n_operands >= 3 + && recog_data.operand_loc[1] == &XEXP (SET_SRC (set), 0) + && recog_data.operand_loc[2] == &XEXP (SET_SRC (set), 1) + && GET_CODE (recog_data.operand[2]) == CONST_INT + && (new = instantiate_new_reg (recog_data.operand[1], &offset))) + { + offset += INTVAL (recog_data.operand[2]); - XEXP (x, 0) = addr; -} - -/* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX - is a virtual register, return the equivalent hard register and set the - offset indirectly through the pointer. Otherwise, return 0. */ + /* If the sum is zero, then replace with a plain move. */ + if (offset == 0) + { + start_sequence (); + emit_move_insn (SET_DEST (set), new); + seq = get_insns (); + end_sequence (); -static rtx -instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset) -{ - rtx new; - HOST_WIDE_INT offset; + emit_insn_before (seq, insn); + delete_insn (insn); + return; + } - if (x == virtual_incoming_args_rtx) - new = arg_pointer_rtx, offset = in_arg_offset; - else if (x == virtual_stack_vars_rtx) - new = frame_pointer_rtx, offset = var_offset; - else if (x == virtual_stack_dynamic_rtx) - new = stack_pointer_rtx, offset = dynamic_offset; - else if (x == virtual_outgoing_args_rtx) - new = stack_pointer_rtx, offset = out_arg_offset; - else if (x == virtual_cfa_rtx) - new = arg_pointer_rtx, offset = cfa_offset; + x = gen_int_mode (offset, recog_data.operand_mode[2]); + insn_code = INSN_CODE (insn); + + /* Using validate_change and apply_change_group here leaves + recog_data in an invalid state. Since we know exactly what + we want to check, do those two by hand. */ + if (safe_insn_predicate (insn_code, 1, new) + && safe_insn_predicate (insn_code, 2, x)) + { + *recog_data.operand_loc[1] = recog_data.operand[1] = new; + *recog_data.operand_loc[2] = recog_data.operand[2] = x; + any_change = true; + goto verify; + } + } + } else - return 0; + extract_insn (insn); - *poffset = offset; - return new; -} - + insn_code = INSN_CODE (insn); + any_change = false; -/* Called when instantiate_virtual_regs has failed to update the instruction. - Usually this means that non-matching instruction has been emit, however for - asm statements it may be the problem in the constraints. */ -static void -instantiate_virtual_regs_lossage (rtx insn) -{ - gcc_assert (asm_noperands (PATTERN (insn)) >= 0); - error_for_asm (insn, "impossible constraint in %"); - delete_insn (insn); -} -/* Given a pointer to a piece of rtx and an optional pointer to the - containing object, instantiate any virtual registers present in it. + /* In the general case, we expect virtual registers to appear only in + operands, and then only as either bare registers or inside memories. */ + for (i = 0; i < recog_data.n_operands; ++i) + { + x = recog_data.operand[i]; + switch (GET_CODE (x)) + { + case MEM: + { + rtx addr = XEXP (x, 0); + bool changed = false; - If EXTRA_INSNS, we always do the replacement and generate - any extra insns before OBJECT. If it zero, we do nothing if replacement - is not valid. + for_each_rtx (&addr, instantiate_virtual_regs_in_rtx, &changed); + if (!changed) + continue; - Return 1 if we either had nothing to do or if we were able to do the - needed replacement. Return 0 otherwise; we only return zero if - EXTRA_INSNS is zero. + start_sequence (); + x = replace_equiv_address (x, addr); + seq = get_insns (); + end_sequence (); + if (seq) + emit_insn_before (seq, insn); + } + break; - We first try some simple transformations to avoid the creation of extra - pseudos. */ + case REG: + new = instantiate_new_reg (x, &offset); + if (new == NULL) + continue; + if (offset == 0) + x = new; + else + { + start_sequence (); -static int -instantiate_virtual_regs_1 (rtx *loc, rtx object, int extra_insns) -{ - rtx x; - RTX_CODE code; - rtx new = 0; - HOST_WIDE_INT offset = 0; - rtx temp; - rtx seq; - int i, j; - const char *fmt; + /* Careful, special mode predicates may have stuff in + insn_data[insn_code].operand[i].mode that isn't useful + to us for computing a new value. */ + /* ??? Recognize address_operand and/or "p" constraints + to see if (plus new offset) is a valid before we put + this through expand_simple_binop. */ + x = expand_simple_binop (GET_MODE (x), PLUS, new, + GEN_INT (offset), NULL_RTX, + 1, OPTAB_LIB_WIDEN); + seq = get_insns (); + end_sequence (); + emit_insn_before (seq, insn); + } + break; - /* Re-start here to avoid recursion in common cases. */ - restart: + case SUBREG: + new = instantiate_new_reg (SUBREG_REG (x), &offset); + if (new == NULL) + continue; + if (offset != 0) + { + start_sequence (); + new = expand_simple_binop (GET_MODE (new), PLUS, new, + GEN_INT (offset), NULL_RTX, + 1, OPTAB_LIB_WIDEN); + seq = get_insns (); + end_sequence (); + emit_insn_before (seq, insn); + } + x = simplify_gen_subreg (insn_data[insn_code].operand[i].mode, + new, GET_MODE (new), SUBREG_BYTE (x)); + break; - x = *loc; - if (x == 0) - return 1; + default: + continue; + } - /* We may have detected and deleted invalid asm statements. */ - if (object && INSN_P (object) && INSN_DELETED_P (object)) - return 1; + /* At this point, X contains the new value for the operand. + Validate the new value vs the insn predicate. Note that + asm insns will have insn_code -1 here. */ + if (!safe_insn_predicate (insn_code, i, x)) + x = force_reg (insn_data[insn_code].operand[i].mode, x); - code = GET_CODE (x); + *recog_data.operand_loc[i] = recog_data.operand[i] = x; + any_change = true; + } - /* Check for some special cases. */ - switch (code) + verify: + if (any_change) { - case CONST_INT: - case CONST_DOUBLE: - case CONST_VECTOR: - case CONST: - case SYMBOL_REF: - case CODE_LABEL: - case PC: - case CC0: - case ASM_INPUT: - case ADDR_VEC: - case ADDR_DIFF_VEC: - case RETURN: - return 1; + /* Propagate operand changes into the duplicates. */ + for (i = 0; i < recog_data.n_dups; ++i) + *recog_data.dup_loc[i] + = recog_data.operand[(unsigned)recog_data.dup_num[i]]; - case SET: - /* We are allowed to set the virtual registers. This means that - the actual register should receive the source minus the - appropriate offset. This is used, for example, in the handling - of non-local gotos. */ - if ((new = instantiate_new_reg (SET_DEST (x), &offset)) != 0) + /* Force re-recognition of the instruction for validation. */ + INSN_CODE (insn) = -1; + } + + if (asm_noperands (PATTERN (insn)) >= 0) + { + if (!check_asm_operands (PATTERN (insn))) { - rtx src = SET_SRC (x); + error_for_asm (insn, "impossible constraint in %"); + delete_insn (insn); + } + } + else + { + if (recog_memoized (insn) < 0) + fatal_insn_not_found (insn); + } +} - /* We are setting the register, not using it, so the relevant - offset is the negative of the offset to use were we using - the register. */ - offset = - offset; - instantiate_virtual_regs_1 (&src, NULL_RTX, 0); +/* Subroutine of instantiate_decls. Given RTL representing a decl, + do any instantiation required. */ - /* The only valid sources here are PLUS or REG. Just do - the simplest possible thing to handle them. */ - if (!REG_P (src) && GET_CODE (src) != PLUS) - { - instantiate_virtual_regs_lossage (object); - return 1; - } +static void +instantiate_decl (rtx x) +{ + rtx addr; - start_sequence (); - if (!REG_P (src)) - temp = force_operand (src, NULL_RTX); - else - temp = src; - temp = force_operand (plus_constant (temp, offset), NULL_RTX); - seq = get_insns (); - end_sequence (); + if (x == 0) + return; - emit_insn_before (seq, object); - SET_DEST (x) = new; + /* If this is a CONCAT, recurse for the pieces. */ + if (GET_CODE (x) == CONCAT) + { + instantiate_decl (XEXP (x, 0)); + instantiate_decl (XEXP (x, 1)); + return; + } - if (! validate_change (object, &SET_SRC (x), temp, 0) - || ! extra_insns) - instantiate_virtual_regs_lossage (object); + /* If this is not a MEM, no need to do anything. Similarly if the + address is a constant or a register that is not a virtual register. */ + if (!MEM_P (x)) + return; - return 1; - } + addr = XEXP (x, 0); + if (CONSTANT_P (addr) + || (REG_P (addr) + && (REGNO (addr) < FIRST_VIRTUAL_REGISTER + || REGNO (addr) > LAST_VIRTUAL_REGISTER))) + return; - instantiate_virtual_regs_1 (&SET_DEST (x), object, extra_insns); - loc = &SET_SRC (x); - goto restart; + for_each_rtx (&XEXP (x, 0), instantiate_virtual_regs_in_rtx, NULL); +} - case PLUS: - /* Handle special case of virtual register plus constant. */ - if (CONSTANT_P (XEXP (x, 1))) - { - rtx old, new_offset; +/* Subroutine of instantiate_decls: Process all decls in the given + BLOCK node and all its subblocks. */ - /* Check for (plus (plus VIRT foo) (const_int)) first. */ - if (GET_CODE (XEXP (x, 0)) == PLUS) - { - if ((new = instantiate_new_reg (XEXP (XEXP (x, 0), 0), &offset))) - { - instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object, - extra_insns); - new = gen_rtx_PLUS (Pmode, new, XEXP (XEXP (x, 0), 1)); - } - else - { - loc = &XEXP (x, 0); - goto restart; - } - } +static void +instantiate_decls_1 (tree let) +{ + tree t; -#ifdef POINTERS_EXTEND_UNSIGNED - /* If we have (plus (subreg (virtual-reg)) (const_int)), we know - we can commute the PLUS and SUBREG because pointers into the - frame are well-behaved. */ - else if (GET_CODE (XEXP (x, 0)) == SUBREG && GET_MODE (x) == ptr_mode - && GET_CODE (XEXP (x, 1)) == CONST_INT - && 0 != (new - = instantiate_new_reg (SUBREG_REG (XEXP (x, 0)), - &offset)) - && validate_change (object, loc, - plus_constant (gen_lowpart (ptr_mode, - new), - offset - + INTVAL (XEXP (x, 1))), - 0)) - return 1; -#endif - else if ((new = instantiate_new_reg (XEXP (x, 0), &offset)) == 0) - { - /* We know the second operand is a constant. Unless the - first operand is a REG (which has been already checked), - it needs to be checked. */ - if (!REG_P (XEXP (x, 0))) - { - loc = &XEXP (x, 0); - goto restart; - } - return 1; - } + for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t)) + if (DECL_RTL_SET_P (t)) + instantiate_decl (DECL_RTL (t)); - new_offset = plus_constant (XEXP (x, 1), offset); - - /* If the new constant is zero, try to replace the sum with just - the register. */ - if (new_offset == const0_rtx - && validate_change (object, loc, new, 0)) - return 1; - - /* Next try to replace the register and new offset. - There are two changes to validate here and we can't assume that - in the case of old offset equals new just changing the register - will yield a valid insn. In the interests of a little efficiency, - however, we only call validate change once (we don't queue up the - changes and then call apply_change_group). */ - - old = XEXP (x, 0); - if (offset == 0 - ? ! validate_change (object, &XEXP (x, 0), new, 0) - : (XEXP (x, 0) = new, - ! validate_change (object, &XEXP (x, 1), new_offset, 0))) - { - if (! extra_insns) - { - XEXP (x, 0) = old; - return 0; - } + /* Process all subblocks. */ + for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t)) + instantiate_decls_1 (t); +} - /* Otherwise copy the new constant into a register and replace - constant with that register. */ - temp = gen_reg_rtx (Pmode); - XEXP (x, 0) = new; - if (validate_change (object, &XEXP (x, 1), temp, 0)) - emit_insn_before (gen_move_insn (temp, new_offset), object); - else - { - /* If that didn't work, replace this expression with a - register containing the sum. */ +/* Scan all decls in FNDECL (both variables and parameters) and instantiate + all virtual registers in their DECL_RTL's. */ - XEXP (x, 0) = old; - new = gen_rtx_PLUS (Pmode, new, new_offset); +static void +instantiate_decls (tree fndecl) +{ + tree decl; - start_sequence (); - temp = force_operand (new, NULL_RTX); - seq = get_insns (); - end_sequence (); + /* Process all parameters of the function. */ + for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl)) + { + instantiate_decl (DECL_RTL (decl)); + instantiate_decl (DECL_INCOMING_RTL (decl)); + } - emit_insn_before (seq, object); - if (! validate_change (object, loc, temp, 0) - && ! validate_replace_rtx (x, temp, object)) - { - instantiate_virtual_regs_lossage (object); - return 1; - } - } - } + /* Now process all variables defined in the function or its subblocks. */ + instantiate_decls_1 (DECL_INITIAL (fndecl)); +} - return 1; - } +/* Pass through the INSNS of function FNDECL and convert virtual register + references to hard register references. */ - /* Fall through to generic two-operand expression case. */ - case EXPR_LIST: - case CALL: - case COMPARE: - case MINUS: - case MULT: - case DIV: case UDIV: - case MOD: case UMOD: - case AND: case IOR: case XOR: - case ROTATERT: case ROTATE: - case ASHIFTRT: case LSHIFTRT: case ASHIFT: - case NE: case EQ: - case GE: case GT: case GEU: case GTU: - case LE: case LT: case LEU: case LTU: - if (XEXP (x, 1) && ! CONSTANT_P (XEXP (x, 1))) - instantiate_virtual_regs_1 (&XEXP (x, 1), object, extra_insns); - loc = &XEXP (x, 0); - goto restart; - - case MEM: - /* Most cases of MEM that convert to valid addresses have already been - handled by our scan of decls. The only special handling we - need here is to make a copy of the rtx to ensure it isn't being - shared if we have to change it to a pseudo. - - If the rtx is a simple reference to an address via a virtual register, - it can potentially be shared. In such cases, first try to make it - a valid address, which can also be shared. Otherwise, copy it and - proceed normally. - - First check for common cases that need no processing. These are - usually due to instantiation already being done on a previous instance - of a shared rtx. */ - - temp = XEXP (x, 0); - if (CONSTANT_ADDRESS_P (temp) -#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM - || temp == arg_pointer_rtx -#endif -#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM - || temp == hard_frame_pointer_rtx -#endif - || temp == frame_pointer_rtx) - return 1; - - if (GET_CODE (temp) == PLUS - && CONSTANT_ADDRESS_P (XEXP (temp, 1)) - && (XEXP (temp, 0) == frame_pointer_rtx -#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM - || XEXP (temp, 0) == hard_frame_pointer_rtx -#endif -#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM - || XEXP (temp, 0) == arg_pointer_rtx -#endif - )) - return 1; - - if (temp == virtual_stack_vars_rtx - || temp == virtual_incoming_args_rtx - || (GET_CODE (temp) == PLUS - && CONSTANT_ADDRESS_P (XEXP (temp, 1)) - && (XEXP (temp, 0) == virtual_stack_vars_rtx - || XEXP (temp, 0) == virtual_incoming_args_rtx))) - { - /* This MEM may be shared. If the substitution can be done without - the need to generate new pseudos, we want to do it in place - so all copies of the shared rtx benefit. The call below will - only make substitutions if the resulting address is still - valid. - - Note that we cannot pass X as the object in the recursive call - since the insn being processed may not allow all valid - addresses. However, if we were not passed on object, we can - only modify X without copying it if X will have a valid - address. - - ??? Also note that this can still lose if OBJECT is an insn that - has less restrictions on an address that some other insn. - In that case, we will modify the shared address. This case - doesn't seem very likely, though. One case where this could - happen is in the case of a USE or CLOBBER reference, but we - take care of that below. */ - - if (instantiate_virtual_regs_1 (&XEXP (x, 0), - object ? object : x, 0)) - return 1; - - /* Otherwise make a copy and process that copy. We copy the entire - RTL expression since it might be a PLUS which could also be - shared. */ - *loc = x = copy_rtx (x); - } +void +instantiate_virtual_regs (void) +{ + rtx insn; - /* Fall through to generic unary operation case. */ - case PREFETCH: - case SUBREG: - case STRICT_LOW_PART: - case NEG: case NOT: - case PRE_DEC: case PRE_INC: case POST_DEC: case POST_INC: - case SIGN_EXTEND: case ZERO_EXTEND: - case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE: - case FLOAT: case FIX: - case UNSIGNED_FIX: case UNSIGNED_FLOAT: - case ABS: - case SQRT: - case FFS: - case CLZ: case CTZ: - case POPCOUNT: case PARITY: - /* These case either have just one operand or we know that we need not - check the rest of the operands. */ - loc = &XEXP (x, 0); - goto restart; - - case USE: - case CLOBBER: - /* If the operand is a MEM, see if the change is a valid MEM. If not, - go ahead and make the invalid one, but do it to a copy. For a REG, - just make the recursive call, since there's no chance of a problem. */ - - if ((MEM_P (XEXP (x, 0)) - && instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), XEXP (x, 0), - 0)) - || (REG_P (XEXP (x, 0)) - && instantiate_virtual_regs_1 (&XEXP (x, 0), object, 0))) - return 1; - - XEXP (x, 0) = copy_rtx (XEXP (x, 0)); - loc = &XEXP (x, 0); - goto restart; + /* Compute the offsets to use for this function. */ + in_arg_offset = FIRST_PARM_OFFSET (current_function_decl); + var_offset = STARTING_FRAME_OFFSET; + dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl); + out_arg_offset = STACK_POINTER_OFFSET; + cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl); - case REG: - /* Try to replace with a PLUS. If that doesn't work, compute the sum - in front of this insn and substitute the temporary. */ - if ((new = instantiate_new_reg (x, &offset)) != 0) - { - temp = plus_constant (new, offset); - if (!validate_change (object, loc, temp, 0)) - { - if (! extra_insns) - return 0; + /* Initialize recognition, indicating that volatile is OK. */ + init_recog (); - start_sequence (); - temp = force_operand (temp, NULL_RTX); - seq = get_insns (); - end_sequence (); + /* Scan through all the insns, instantiating every virtual register still + present. */ + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (INSN_P (insn)) + { + /* These patterns in the instruction stream can never be recognized. + Fortunately, they shouldn't contain virtual registers either. */ + if (GET_CODE (PATTERN (insn)) == USE + || GET_CODE (PATTERN (insn)) == CLOBBER + || GET_CODE (PATTERN (insn)) == ADDR_VEC + || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC + || GET_CODE (PATTERN (insn)) == ASM_INPUT) + continue; - emit_insn_before (seq, object); - if (! validate_change (object, loc, temp, 0) - && ! validate_replace_rtx (x, temp, object)) - instantiate_virtual_regs_lossage (object); - } - } + instantiate_virtual_regs_in_insn (insn); - return 1; + if (INSN_DELETED_P (insn)) + continue; - default: - break; - } + for_each_rtx (®_NOTES (insn), instantiate_virtual_regs_in_rtx, NULL); - /* Scan all subexpressions. */ - fmt = GET_RTX_FORMAT (code); - for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) - if (*fmt == 'e') - { - if (!instantiate_virtual_regs_1 (&XEXP (x, i), object, extra_insns)) - return 0; + /* Instantiate any virtual registers in CALL_INSN_FUNCTION_USAGE. */ + if (GET_CODE (insn) == CALL_INSN) + for_each_rtx (&CALL_INSN_FUNCTION_USAGE (insn), + instantiate_virtual_regs_in_rtx, NULL); } - else if (*fmt == 'E') - for (j = 0; j < XVECLEN (x, i); j++) - if (! instantiate_virtual_regs_1 (&XVECEXP (x, i, j), object, - extra_insns)) - return 0; - return 1; + /* Instantiate the virtual registers in the DECLs for debugging purposes. */ + instantiate_decls (current_function_decl); + + /* Indicate that, from now on, assign_stack_local should use + frame_pointer_rtx. */ + virtuals_instantiated = 1; } /* Return 1 if EXP is an aggregate type (or a value with aggregate type).