📄 function.c
字号:
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;}; /* Forward declarations. */static struct temp_slot *find_temp_slot_from_address PROTO((rtx));static void put_reg_into_stack PROTO((struct function *, rtx, tree, enum machine_mode, enum machine_mode, int, int));static void fixup_var_refs PROTO((rtx, enum machine_mode, int));static struct fixup_replacement *find_fixup_replacement PROTO((struct fixup_replacement **, rtx));static void fixup_var_refs_insns PROTO((rtx, enum machine_mode, int, rtx, int));static void fixup_var_refs_1 PROTO((rtx, enum machine_mode, rtx *, rtx, struct fixup_replacement **));static rtx fixup_memory_subreg PROTO((rtx, rtx, int));static rtx walk_fixup_memory_subreg PROTO((rtx, rtx, int));static rtx fixup_stack_1 PROTO((rtx, rtx));static void optimize_bit_field PROTO((rtx, rtx, rtx *));static void instantiate_decls PROTO((tree, int));static void instantiate_decls_1 PROTO((tree, int));static void instantiate_decl PROTO((rtx, int, int));static int instantiate_virtual_regs_1 PROTO((rtx *, rtx, int));static void delete_handlers PROTO((void));static void pad_to_arg_alignment PROTO((struct args_size *, int));static void pad_below PROTO((struct args_size *, enum machine_mode, tree));static tree round_down PROTO((tree, int));static rtx round_trampoline_addr PROTO((rtx));static tree blocks_nreverse PROTO((tree));static int all_blocks PROTO((tree, tree *));static int *record_insns PROTO((rtx));static int contains PROTO((rtx, int *));static void put_addressof_into_stack PROTO((rtx));static void purge_addressof_1 PROTO((rtx *, rtx, int));/* Pointer to chain of `struct function' for containing functions. */struct function *outer_function_chain;/* Given a function decl for a containing function, return the `struct function' for it. */struct function *find_function_data (decl) tree decl;{ struct function *p; for (p = outer_function_chain; p; p = p->next) if (p->decl == decl) return p; abort ();}/* Save the current context for compilation of a nested function. This is called from language-specific code. The caller is responsible for saving any language-specific status, since this function knows only about language-independent variables. */voidpush_function_context_to (context) tree context;{ struct function *p = (struct function *) xmalloc (sizeof (struct function)); p->next = outer_function_chain; outer_function_chain = p; p->name = current_function_name; p->decl = current_function_decl; p->pops_args = current_function_pops_args; p->returns_struct = current_function_returns_struct; p->returns_pcc_struct = current_function_returns_pcc_struct; p->returns_pointer = current_function_returns_pointer; p->needs_context = current_function_needs_context; p->calls_setjmp = current_function_calls_setjmp; p->calls_longjmp = current_function_calls_longjmp; p->calls_alloca = current_function_calls_alloca; p->has_nonlocal_label = current_function_has_nonlocal_label; p->has_nonlocal_goto = current_function_has_nonlocal_goto; p->contains_functions = current_function_contains_functions; p->is_thunk = current_function_is_thunk; p->args_size = current_function_args_size; p->pretend_args_size = current_function_pretend_args_size; p->arg_offset_rtx = current_function_arg_offset_rtx; p->varargs = current_function_varargs; p->stdarg = current_function_stdarg; p->uses_const_pool = current_function_uses_const_pool; p->uses_pic_offset_table = current_function_uses_pic_offset_table; p->internal_arg_pointer = current_function_internal_arg_pointer; p->max_parm_reg = max_parm_reg; p->parm_reg_stack_loc = parm_reg_stack_loc; p->outgoing_args_size = current_function_outgoing_args_size; p->return_rtx = current_function_return_rtx; p->nonlocal_goto_handler_slot = nonlocal_goto_handler_slot; p->nonlocal_goto_stack_level = nonlocal_goto_stack_level; p->nonlocal_labels = nonlocal_labels; p->cleanup_label = cleanup_label; p->return_label = return_label; p->save_expr_regs = save_expr_regs; p->stack_slot_list = stack_slot_list; p->parm_birth_insn = parm_birth_insn; p->frame_offset = frame_offset; p->tail_recursion_label = tail_recursion_label; p->tail_recursion_reentry = tail_recursion_reentry; p->arg_pointer_save_area = arg_pointer_save_area; p->rtl_expr_chain = rtl_expr_chain; p->last_parm_insn = last_parm_insn; p->context_display = context_display; p->trampoline_list = trampoline_list; p->function_call_count = function_call_count; p->temp_slots = temp_slots; p->temp_slot_level = temp_slot_level; p->fixup_var_refs_queue = 0; p->epilogue_delay_list = current_function_epilogue_delay_list; p->args_info = current_function_args_info; save_tree_status (p, context); save_storage_status (p); save_emit_status (p); init_emit (); save_expr_status (p); save_stmt_status (p); save_varasm_status (p, context); if (save_machine_status) (*save_machine_status) (p);}voidpush_function_context (){ push_function_context_to (current_function_decl);}/* Restore the last saved context, at the end of a nested function. This function is called from language-specific code. */voidpop_function_context_from (context) tree context;{ struct function *p = outer_function_chain; outer_function_chain = p->next; current_function_contains_functions = p->contains_functions || p->inline_obstacks || context == current_function_decl; current_function_name = p->name; current_function_decl = p->decl; current_function_pops_args = p->pops_args; current_function_returns_struct = p->returns_struct; current_function_returns_pcc_struct = p->returns_pcc_struct; current_function_returns_pointer = p->returns_pointer; current_function_needs_context = p->needs_context; current_function_calls_setjmp = p->calls_setjmp; current_function_calls_longjmp = p->calls_longjmp; current_function_calls_alloca = p->calls_alloca; current_function_has_nonlocal_label = p->has_nonlocal_label; current_function_has_nonlocal_goto = p->has_nonlocal_goto; current_function_is_thunk = p->is_thunk; current_function_args_size = p->args_size; current_function_pretend_args_size = p->pretend_args_size; current_function_arg_offset_rtx = p->arg_offset_rtx; current_function_varargs = p->varargs; current_function_stdarg = p->stdarg; current_function_uses_const_pool = p->uses_const_pool; current_function_uses_pic_offset_table = p->uses_pic_offset_table; current_function_internal_arg_pointer = p->internal_arg_pointer; max_parm_reg = p->max_parm_reg; parm_reg_stack_loc = p->parm_reg_stack_loc; current_function_outgoing_args_size = p->outgoing_args_size; current_function_return_rtx = p->return_rtx; nonlocal_goto_handler_slot = p->nonlocal_goto_handler_slot; nonlocal_goto_stack_level = p->nonlocal_goto_stack_level; nonlocal_labels = p->nonlocal_labels; cleanup_label = p->cleanup_label; return_label = p->return_label; save_expr_regs = p->save_expr_regs; stack_slot_list = p->stack_slot_list; parm_birth_insn = p->parm_birth_insn; frame_offset = p->frame_offset; tail_recursion_label = p->tail_recursion_label; tail_recursion_reentry = p->tail_recursion_reentry; arg_pointer_save_area = p->arg_pointer_save_area; rtl_expr_chain = p->rtl_expr_chain; last_parm_insn = p->last_parm_insn; context_display = p->context_display; trampoline_list = p->trampoline_list; function_call_count = p->function_call_count; temp_slots = p->temp_slots; temp_slot_level = p->temp_slot_level; current_function_epilogue_delay_list = p->epilogue_delay_list; reg_renumber = 0; current_function_args_info = p->args_info; restore_tree_status (p, context); restore_storage_status (p); restore_expr_status (p); restore_emit_status (p); restore_stmt_status (p); restore_varasm_status (p); if (restore_machine_status) (*restore_machine_status) (p); /* Finish doing put_var_into_stack for any of our variables which became addressable during the nested function. */ { struct var_refs_queue *queue = p->fixup_var_refs_queue; for (; queue; queue = queue->next) fixup_var_refs (queue->modified, queue->promoted_mode, queue->unsignedp); } free (p); /* Reset variables that have known state during rtx generation. */ rtx_equal_function_value_matters = 1; virtuals_instantiated = 0;}void pop_function_context (){ pop_function_context_from (current_function_decl);}/* Allocate fixed slots in the stack frame of the current function. *//* Return size needed for stack frame based on slots so far allocated. This size counts from zero. It is not rounded to STACK_BOUNDARY; the caller may have to do that. */HOST_WIDE_INTget_frame_size (){#ifdef FRAME_GROWS_DOWNWARD return -frame_offset;#else return frame_offset;#endif}/* Allocate a stack slot of SIZE bytes and return a MEM rtx for it with machine mode MODE. ALIGN controls the amount of alignment for the address of the slot: 0 means according to MODE, -1 means use BIGGEST_ALIGNMENT and round size to multiple of that, positive specifies alignment boundary in bits. We do not round to stack_boundary here. */rtxassign_stack_local (mode, size, align) enum machine_mode mode; int size; int align;{ register rtx x, addr; int bigend_correction = 0; int alignment; if (align == 0) { alignment = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; if (mode == BLKmode) alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT; } else if (align == -1) { alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT; size = CEIL_ROUND (size, alignment); } else alignment = align / BITS_PER_UNIT; /* Round frame offset to that alignment. We must be careful here, since FRAME_OFFSET might be negative and division with a negative dividend isn't as well defined as we might like. So we instead assume that ALIGNMENT is a power of two and use logical operations which are unambiguous. */#ifdef FRAME_GROWS_DOWNWARD frame_offset = FLOOR_ROUND (frame_offset, alignment);#else frame_offset = CEIL_ROUND (frame_offset, alignment);#endif /* On a big-endian machine, if we are allocating more space than we will use, use the least significant bytes of those that are allocated. */ if (BYTES_BIG_ENDIAN && mode != BLKmode) bigend_correction = size - GET_MODE_SIZE (mode);#ifdef FRAME_GROWS_DOWNWARD frame_offset -= size;#endif /* If we have already instantiated virtual registers, return the actual address relative to the frame pointer. */ if (virtuals_instantiated) addr = plus_constant (frame_pointer_rtx, (frame_offset + bigend_correction + STARTING_FRAME_OFFSET)); else addr = plus_constant (virtual_stack_vars_rtx, frame_offset + bigend_correction);#ifndef FRAME_GROWS_DOWNWARD frame_offset += size;#endif x = gen_rtx (MEM, mode, addr); stack_slot_list = gen_rtx (EXPR_LIST, VOIDmode, x, stack_slot_list); return x;}/* Assign a stack slot in a containing function. First three arguments are same as in preceding function. The last argument specifies the function to allocate in. */rtxassign_outer_stack_local (mode, size, align, function) enum machine_mode mode; int size; int align; struct function *function;{ register rtx x, addr; int bigend_correction = 0; int alignment; /* Allocate in the memory associated with the function in whose frame we are assigning. */ push_obstacks (function->function_obstack, function->function_maybepermanent_obstack); if (align == 0) { alignment = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT; if (mode == BLKmode) alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT; } else if (align == -1) { alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT; size = CEIL_ROUND (size, alignment); } else alignment = align / BITS_PER_UNIT; /* Round frame offset to that alignment. */#ifdef FRAME_GROWS_DOWNWARD function->frame_offset = FLOOR_ROUND (function->frame_offset, alignment);#else function->frame_offset = CEIL_ROUND (function->frame_offset, alignment);#endif /* On a big-endian machine, if we are allocating more space than we will use, use the least significant bytes of those that are allocated. */ if (BYTES_BIG_ENDIAN && mode != BLKmode) bigend_correction = size - GET_MODE_SIZE (mode);#ifdef FRAME_GROWS_DOWNWARD function->frame_offset -= size;#endif addr = plus_constant (virtual_stack_vars_rtx, function->frame_offset + bigend_correction);#ifndef FRAME_GROWS_DOWNWARD function->frame_offset += size;#endif x = gen_rtx (MEM, mode, addr); function->stack_slot_list = gen_rtx (EXPR_LIST, VOIDmode, x, function->stack_slot_list); pop_obstacks (); return x;}/* Allocate a temporary stack slot and record it for possible later reuse. MODE is the machine mode to be given to the returned rtx. SIZE is the size in units of the space required. We do no rounding here since assign_stack_local will do any required rounding. KEEP is 1 if this slot is to be retained after a call to free_temp_slots. Automatic variables for a block are allocated with this flag. KEEP is 2, if we allocate a longer term temporary, whose lifetime is controlled by CLEANUP_POINT_EXPRs. */rtxassign_stack_temp (mode, size, keep) enum machine_mode mode; int size; int keep;{ struct temp_slot *p, *best_p = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -