diff options
author | H.J. Lu <hongjiu.lu@intel.com> | 2010-07-23 19:37:40 +0000 |
---|---|---|
committer | H.J. Lu <hongjiu.lu@intel.com> | 2010-07-23 19:37:40 +0000 |
commit | e59b0ef2e7a1fb44791d473ee416aeb01fcb169c (patch) | |
tree | 437dca120093cc7b1f6debf6f6b31779526c7192 /gcc/function.c | |
parent | f25b023a0d9de6a6c1e1965d93ba6028cb03fc7d (diff) | |
parent | 92ac755201aad4366eaff2b75b3239637bee3590 (diff) |
Merged with trunk at revision 162480.ifunc
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/ifunc@162483 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/function.c')
-rw-r--r-- | gcc/function.c | 138 |
1 files changed, 108 insertions, 30 deletions
diff --git a/gcc/function.c b/gcc/function.c index 3a7bb25dac6..5a308f44505 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -1793,7 +1793,7 @@ instantiate_decls_1 (tree let) { tree t; - for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t)) + for (t = BLOCK_VARS (let); t; t = DECL_CHAIN (t)) { if (DECL_RTL_SET_P (t)) instantiate_decl_rtl (DECL_RTL (t)); @@ -1815,10 +1815,11 @@ instantiate_decls_1 (tree let) static void instantiate_decls (tree fndecl) { - tree decl, t, next; + tree decl; + unsigned ix; /* Process all parameters of the function. */ - for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl)) + for (decl = DECL_ARGUMENTS (fndecl); decl; decl = DECL_CHAIN (decl)) { instantiate_decl_rtl (DECL_RTL (decl)); instantiate_decl_rtl (DECL_INCOMING_RTL (decl)); @@ -1832,16 +1833,10 @@ instantiate_decls (tree fndecl) /* Now process all variables defined in the function or its subblocks. */ instantiate_decls_1 (DECL_INITIAL (fndecl)); - t = cfun->local_decls; - cfun->local_decls = NULL_TREE; - for (; t; t = next) - { - next = TREE_CHAIN (t); - decl = TREE_VALUE (t); - if (DECL_RTL_SET_P (decl)) - instantiate_decl_rtl (DECL_RTL (decl)); - ggc_free (t); - } + FOR_EACH_LOCAL_DECL (cfun, ix, decl) + if (DECL_RTL_SET_P (decl)) + instantiate_decl_rtl (DECL_RTL (decl)); + VEC_free (tree, gc, cfun->local_decls); } /* Pass through the INSNS of function FNDECL and convert virtual register @@ -2227,7 +2222,7 @@ assign_parms_augmented_arg_list (struct assign_parm_data_all *all) VEC(tree, heap) *fnargs = NULL; tree arg; - for (arg = DECL_ARGUMENTS (fndecl); arg; arg = TREE_CHAIN (arg)) + for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg)) VEC_safe_push (tree, heap, fnargs, arg); all->orig_fnargs = DECL_ARGUMENTS (fndecl); @@ -2246,7 +2241,7 @@ assign_parms_augmented_arg_list (struct assign_parm_data_all *all) DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; - TREE_CHAIN (decl) = all->orig_fnargs; + DECL_CHAIN (decl) = all->orig_fnargs; all->orig_fnargs = decl; VEC_safe_insert (tree, heap, fnargs, 0, decl); @@ -2277,7 +2272,7 @@ assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm, /* NAMED_ARG is a misnomer. We really mean 'non-variadic'. */ if (!cfun->stdarg) data->named_arg = 1; /* No variadic parms. */ - else if (TREE_CHAIN (parm)) + else if (DECL_CHAIN (parm)) data->named_arg = 1; /* Not the last non-variadic parm. */ else if (targetm.calls.strict_argument_naming (&all->args_so_far)) data->named_arg = 1; /* Only variadic ones are unnamed. */ @@ -2859,6 +2854,21 @@ assign_parm_setup_block (struct assign_parm_data_all *all, SET_DECL_RTL (parm, stack_parm); } +/* A subroutine of assign_parm_setup_reg, called through note_stores. + This collects sets and clobbers of hard registers in a HARD_REG_SET, + which is pointed to by DATA. */ +static void +record_hard_reg_sets (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data) +{ + HARD_REG_SET *pset = (HARD_REG_SET *)data; + if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER) + { + int nregs = hard_regno_nregs[REGNO (x)][GET_MODE (x)]; + while (nregs-- > 0) + SET_HARD_REG_BIT (*pset, REGNO (x) + nregs); + } +} + /* A subroutine of assign_parms. Allocate a pseudo to hold the current parameter. Get it there. Perform all ABI specified conversions. */ @@ -2866,10 +2876,12 @@ static void assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm, struct assign_parm_data_one *data) { - rtx parmreg; + rtx parmreg, validated_mem; + rtx equiv_stack_parm; enum machine_mode promoted_nominal_mode; int unsignedp = TYPE_UNSIGNED (TREE_TYPE (parm)); bool did_conversion = false; + bool need_conversion, moved; /* Store the parm in a pseudoregister during the function, but we may need to do it in a wider mode. Using 2 here makes the result @@ -2898,11 +2910,19 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm, /* Copy the value into the register, thus bridging between assign_parm_find_data_types and expand_expr_real_1. */ - if (data->nominal_mode != data->passed_mode - || promoted_nominal_mode != data->promoted_mode) - { - int save_tree_used; + equiv_stack_parm = data->stack_parm; + validated_mem = validize_mem (data->entry_parm); + + need_conversion = (data->nominal_mode != data->passed_mode + || promoted_nominal_mode != data->promoted_mode); + moved = false; + + if (need_conversion + && GET_MODE_CLASS (data->nominal_mode) == MODE_INT + && data->nominal_mode == data->passed_mode + && data->nominal_mode == GET_MODE (data->entry_parm)) + { /* ENTRY_PARM has been converted to PROMOTED_MODE, its mode, by the caller. We now have to convert it to NOMINAL_MODE, if different. However, PARMREG may be in @@ -2918,13 +2938,71 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm, In addition, the conversion may involve a call, which could clobber parameters which haven't been copied to pseudo - registers yet. Therefore, we must first copy the parm to - a pseudo reg here, and save the conversion until after all + registers yet. + + First, we try to emit an insn which performs the necessary + conversion. We verify that this insn does not clobber any + hard registers. */ + + enum insn_code icode; + rtx op0, op1; + + icode = can_extend_p (promoted_nominal_mode, data->passed_mode, + unsignedp); + + op0 = parmreg; + op1 = validated_mem; + if (icode != CODE_FOR_nothing + && insn_data[icode].operand[0].predicate (op0, promoted_nominal_mode) + && insn_data[icode].operand[1].predicate (op1, data->passed_mode)) + { + enum rtx_code code = unsignedp ? ZERO_EXTEND : SIGN_EXTEND; + rtx insn, insns; + HARD_REG_SET hardregs; + + start_sequence (); + insn = gen_extend_insn (op0, op1, promoted_nominal_mode, + data->passed_mode, unsignedp); + emit_insn (insn); + insns = get_insns (); + + moved = true; + CLEAR_HARD_REG_SET (hardregs); + for (insn = insns; insn && moved; insn = NEXT_INSN (insn)) + { + if (INSN_P (insn)) + note_stores (PATTERN (insn), record_hard_reg_sets, + &hardregs); + if (!hard_reg_set_empty_p (hardregs)) + moved = false; + } + + end_sequence (); + + if (moved) + { + emit_insn (insns); + if (equiv_stack_parm != NULL_RTX) + equiv_stack_parm = gen_rtx_fmt_e (code, GET_MODE (parmreg), + equiv_stack_parm); + } + } + } + + if (moved) + /* Nothing to do. */ + ; + else if (need_conversion) + { + /* We did not have an insn to convert directly, or the sequence + generated appeared unsafe. We must first copy the parm to a + pseudo reg, and save the conversion until after all parameters have been moved. */ + int save_tree_used; rtx tempreg = gen_reg_rtx (GET_MODE (data->entry_parm)); - emit_move_insn (tempreg, validize_mem (data->entry_parm)); + emit_move_insn (tempreg, validated_mem); push_to_sequence2 (all->first_conversion_insn, all->last_conversion_insn); tempreg = convert_to_mode (data->nominal_mode, tempreg, unsignedp); @@ -2954,7 +3032,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm, did_conversion = true; } else - emit_move_insn (parmreg, validize_mem (data->entry_parm)); + emit_move_insn (parmreg, validated_mem); /* If we were passed a pointer but the actual value can safely live in a register, put it in one. */ @@ -3039,7 +3117,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm, } else if ((set = single_set (linsn)) != 0 && SET_DEST (set) == parmreg) - set_unique_reg_note (linsn, REG_EQUIV, data->stack_parm); + set_unique_reg_note (linsn, REG_EQUIV, equiv_stack_parm); } /* For pointer data type, suggest pointer register. */ @@ -3250,7 +3328,7 @@ assign_parms (tree fndecl) } } - if (cfun->stdarg && !TREE_CHAIN (parm)) + if (cfun->stdarg && !DECL_CHAIN (parm)) assign_parms_setup_varargs (&all, &data, false); /* Find out where the parameter arrives in this function. */ @@ -3830,7 +3908,7 @@ setjmp_vars_warning (bitmap setjmp_crosses, tree block) { tree decl, sub; - for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl)) + for (decl = BLOCK_VARS (block); decl; decl = DECL_CHAIN (decl)) { if (TREE_CODE (decl) == VAR_DECL && DECL_RTL_SET_P (decl) @@ -3852,7 +3930,7 @@ setjmp_args_warning (bitmap setjmp_crosses) { tree decl; for (decl = DECL_ARGUMENTS (current_function_decl); - decl; decl = TREE_CHAIN (decl)) + decl; decl = DECL_CHAIN (decl)) if (DECL_RTL (decl) != 0 && REG_P (DECL_RTL (decl)) && regno_clobbered_at_setjmp (setjmp_crosses, REGNO (DECL_RTL (decl)))) @@ -4694,7 +4772,7 @@ do_warn_unused_parameter (tree fn) tree decl; for (decl = DECL_ARGUMENTS (fn); - decl; decl = TREE_CHAIN (decl)) + decl; decl = DECL_CHAIN (decl)) if (!TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL && DECL_NAME (decl) && !DECL_ARTIFICIAL (decl) && !TREE_NO_WARNING (decl)) |