📄 stmt.c
字号:
int block_start_count; /* The outermost stack level that should be restored for this jump. Each time a binding contour that resets the stack is exited, if the target label is *not* yet defined, this slot is updated. */ rtx stack_level; /* List of lists of cleanup expressions to be run by this goto. There is one element for each block that this goto is within. The tail of this list can be 0, if all remaining elements would be empty. The TREE_VALUE contains the cleanup list of that block as of the time this goto was seen. The TREE_ADDRESSABLE flag is 1 for a block that has been exited. */ tree cleanup_list_list; /* Bytecode specific members follow */ /* The label that this jump is jumping to, or 0 for break, continue or return. */ struct bc_label *bc_target; /* The label we use for the fixup patch */ struct bc_label *label; /* True (non-0) if fixup has been handled */ int bc_handled:1; /* Like stack_level above, except refers to the interpreter stack */ int bc_stack_level;};static struct goto_fixup *goto_fixup_chain;/* Within any binding contour that must restore a stack level, all labels are recorded with a chain of these structures. */struct label_chain{ /* Points to following fixup. */ struct label_chain *next; tree label;};/* Non-zero if we are using EH to handle cleanus. */static int using_eh_for_cleanups_p = 0;static void expand_goto_internal PROTO((tree, rtx, rtx));static void bc_expand_goto_internal PROTO((enum bytecode_opcode, struct bc_label *, tree));static int expand_fixup PROTO((tree, rtx, rtx));static void bc_expand_fixup PROTO((enum bytecode_opcode, struct bc_label *, int));static void fixup_gotos PROTO((struct nesting *, rtx, tree, rtx, int));static void bc_fixup_gotos PROTO((struct nesting *, int, tree, rtx, int));static void bc_expand_start_cond PROTO((tree, int));static void bc_expand_end_cond PROTO((void));static void bc_expand_start_else PROTO((void));static void bc_expand_end_loop PROTO((void));static void bc_expand_end_bindings PROTO((tree, int, int));static void bc_expand_decl PROTO((tree, tree));static void bc_expand_variable_local_init PROTO((tree));static void bc_expand_decl_init PROTO((tree));static void expand_null_return_1 PROTO((rtx, int));static void expand_value_return PROTO((rtx));static int tail_recursion_args PROTO((tree, tree));static void expand_cleanups PROTO((tree, tree, int, int));static void bc_expand_start_case PROTO((struct nesting *, tree, tree, char *));static int bc_pushcase PROTO((tree, tree));static void bc_check_for_full_enumeration_handling PROTO((tree));static void bc_expand_end_case PROTO((tree));static void do_jump_if_equal PROTO((rtx, rtx, rtx, int));static int estimate_case_costs PROTO((case_node_ptr));static void group_case_nodes PROTO((case_node_ptr));static void balance_case_nodes PROTO((case_node_ptr *, case_node_ptr));static int node_has_low_bound PROTO((case_node_ptr, tree));static int node_has_high_bound PROTO((case_node_ptr, tree));static int node_is_bounded PROTO((case_node_ptr, tree));static void emit_jump_if_reachable PROTO((rtx));static void emit_case_nodes PROTO((rtx, case_node_ptr, rtx, tree));static int add_case_node PROTO((tree, tree, tree, tree *));static struct case_node *case_tree2list PROTO((case_node *, case_node *));extern rtx bc_allocate_local ();extern rtx bc_allocate_variable_array ();voidusing_eh_for_cleanups (){ using_eh_for_cleanups_p = 1;}voidinit_stmt (){ gcc_obstack_init (&stmt_obstack); init_eh ();}voidinit_stmt_for_function (){ /* We are not currently within any block, conditional, loop or case. */ block_stack = 0; stack_block_stack = 0; loop_stack = 0; case_stack = 0; cond_stack = 0; nesting_stack = 0; nesting_depth = 0; block_start_count = 0; /* No gotos have been expanded yet. */ goto_fixup_chain = 0; /* We are not processing a ({...}) grouping. */ expr_stmts_for_value = 0; last_expr_type = 0; init_eh_for_function ();}voidsave_stmt_status (p) struct function *p;{ p->block_stack = block_stack; p->stack_block_stack = stack_block_stack; p->cond_stack = cond_stack; p->loop_stack = loop_stack; p->case_stack = case_stack; p->nesting_stack = nesting_stack; p->nesting_depth = nesting_depth; p->block_start_count = block_start_count; p->last_expr_type = last_expr_type; p->last_expr_value = last_expr_value; p->expr_stmts_for_value = expr_stmts_for_value; p->emit_filename = emit_filename; p->emit_lineno = emit_lineno; p->goto_fixup_chain = goto_fixup_chain; save_eh_status (p);}voidrestore_stmt_status (p) struct function *p;{ block_stack = p->block_stack; stack_block_stack = p->stack_block_stack; cond_stack = p->cond_stack; loop_stack = p->loop_stack; case_stack = p->case_stack; nesting_stack = p->nesting_stack; nesting_depth = p->nesting_depth; block_start_count = p->block_start_count; last_expr_type = p->last_expr_type; last_expr_value = p->last_expr_value; expr_stmts_for_value = p->expr_stmts_for_value; emit_filename = p->emit_filename; emit_lineno = p->emit_lineno; goto_fixup_chain = p->goto_fixup_chain; restore_eh_status (p);}/* Emit a no-op instruction. */voidemit_nop (){ rtx last_insn; if (!output_bytecode) { last_insn = get_last_insn (); if (!optimize && (GET_CODE (last_insn) == CODE_LABEL || (GET_CODE (last_insn) == NOTE && prev_real_insn (last_insn) == 0))) emit_insn (gen_nop ()); }}/* Return the rtx-label that corresponds to a LABEL_DECL, creating it if necessary. */rtxlabel_rtx (label) tree label;{ if (TREE_CODE (label) != LABEL_DECL) abort (); if (DECL_RTL (label)) return DECL_RTL (label); return DECL_RTL (label) = gen_label_rtx ();}/* Add an unconditional jump to LABEL as the next sequential instruction. */voidemit_jump (label) rtx label;{ do_pending_stack_adjust (); emit_jump_insn (gen_jump (label)); emit_barrier ();}/* Emit code to jump to the address specified by the pointer expression EXP. */voidexpand_computed_goto (exp) tree exp;{ if (output_bytecode) { bc_expand_expr (exp); bc_emit_instruction (jumpP); } else { rtx x = expand_expr (exp, NULL_RTX, VOIDmode, 0);#ifdef POINTERS_EXTEND_UNSIGNED x = convert_memory_address (Pmode, x);#endif emit_queue (); /* Be sure the function is executable. */ if (flag_check_memory_usage) emit_library_call (chkr_check_exec_libfunc, 1, VOIDmode, 1, x, ptr_mode); do_pending_stack_adjust (); emit_indirect_jump (x); }}/* Handle goto statements and the labels that they can go to. *//* Specify the location in the RTL code of a label LABEL, which is a LABEL_DECL tree node. This is used for the kind of label that the user can jump to with a goto statement, and for alternatives of a switch or case statement. RTL labels generated for loops and conditionals don't go through here; they are generated directly at the RTL level, by other functions below. Note that this has nothing to do with defining label *names*. Languages vary in how they do that and what that even means. */voidexpand_label (label) tree label;{ struct label_chain *p; if (output_bytecode) { if (! DECL_RTL (label)) DECL_RTL (label) = bc_gen_rtx ((char *) 0, 0, bc_get_bytecode_label ()); if (! bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (DECL_RTL (label)))) error ("multiply defined label"); return; } do_pending_stack_adjust (); emit_label (label_rtx (label)); if (DECL_NAME (label)) LABEL_NAME (DECL_RTL (label)) = IDENTIFIER_POINTER (DECL_NAME (label)); if (stack_block_stack != 0) { p = (struct label_chain *) oballoc (sizeof (struct label_chain)); p->next = stack_block_stack->data.block.label_chain; stack_block_stack->data.block.label_chain = p; p->label = label; }}/* Declare that LABEL (a LABEL_DECL) may be used for nonlocal gotos from nested functions. */voiddeclare_nonlocal_label (label) tree label;{ nonlocal_labels = tree_cons (NULL_TREE, label, nonlocal_labels); LABEL_PRESERVE_P (label_rtx (label)) = 1; if (nonlocal_goto_handler_slot == 0) { nonlocal_goto_handler_slot = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0); emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, PREV_INSN (tail_recursion_reentry)); }}/* Generate RTL code for a `goto' statement with target label LABEL. LABEL should be a LABEL_DECL tree node that was or will later be defined with `expand_label'. */voidexpand_goto (label) tree label;{ tree context; if (output_bytecode) { expand_goto_internal (label, label_rtx (label), NULL_RTX); return; } /* Check for a nonlocal goto to a containing function. */ context = decl_function_context (label); if (context != 0 && context != current_function_decl) { struct function *p = find_function_data (context); rtx label_ref = gen_rtx (LABEL_REF, Pmode, label_rtx (label)); rtx temp; p->has_nonlocal_label = 1; current_function_has_nonlocal_goto = 1; LABEL_REF_NONLOCAL_P (label_ref) = 1; /* Copy the rtl for the slots so that they won't be shared in case the virtual stack vars register gets instantiated differently in the parent than in the child. */#if HAVE_nonlocal_goto if (HAVE_nonlocal_goto) emit_insn (gen_nonlocal_goto (lookup_static_chain (label), copy_rtx (p->nonlocal_goto_handler_slot), copy_rtx (p->nonlocal_goto_stack_level), label_ref)); else#endif { rtx addr; /* Restore frame pointer for containing function. This sets the actual hard register used for the frame pointer to the location of the function's incoming static chain info. The non-local goto handler will then adjust it to contain the proper value and reload the argument pointer, if needed. */ emit_move_insn (hard_frame_pointer_rtx, lookup_static_chain (label)); /* We have now loaded the frame pointer hardware register with the address of that corresponds to the start of the virtual stack vars. So replace virtual_stack_vars_rtx in all addresses we use with stack_pointer_rtx. */ /* Get addr of containing function's current nonlocal goto handler, which will do any cleanups and then jump to the label. */ addr = copy_rtx (p->nonlocal_goto_handler_slot); temp = copy_to_reg (replace_rtx (addr, virtual_stack_vars_rtx, hard_frame_pointer_rtx)); /* Restore the stack pointer. Note this uses fp just restored. */ addr = p->nonlocal_goto_stack_level; if (addr) addr = replace_rtx (copy_rtx (addr), virtual_stack_vars_rtx, hard_frame_pointer_rtx); emit_stack_restore (SAVE_NONLOCAL, addr, NULL_RTX); /* Put in the static chain register the nonlocal label address. */ emit_move_insn (static_chain_rtx, label_ref); /* USE of hard_frame_pointer_rtx added for consistency; not clear if really needed. */ emit_insn (gen_rtx (USE, VOIDmode, hard_frame_pointer_rtx)); emit_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx)); emit_insn (gen_rtx (USE, VOIDmode, static_chain_rtx)); emit_indirect_jump (temp); } } else expand_goto_internal (label, label_rtx (label), NULL_RTX);}/* Generate RTL code for a `goto' statement with target label BODY. LABEL should be a LABEL_REF. LAST_INSN, if non-0, is the rtx we should consider as the last insn emitted (for the purposes of cleaning up a return). */static voidexpand_goto_internal (body, label, last_insn) tree body; rtx label; rtx last_insn;{ struct nesting *block; rtx stack_level = 0; /* NOTICE! If a bytecode instruction other than `jump' is needed, then the caller has to call bc_expand_goto_internal()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -