📄 stmt.c
字号:
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;};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));extern rtx bc_allocate_local ();extern rtx bc_allocate_variable_array ();voidinit_stmt (){ gcc_obstack_init (&stmt_obstack);#if 0 empty_cleanup_list = build_tree_list (NULL_TREE, NULL_TREE);#endif}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;}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;}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;}/* 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 (); 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() directly. This is rather an exceptional case, and there aren't that many places where this is necessary. */ if (output_bytecode) { expand_goto_internal (body, label, last_insn); return; } if (GET_CODE (label) != CODE_LABEL) abort (); /* If label has already been defined, we can tell now whether and how we must alter the stack level. */ if (PREV_INSN (label) != 0) { /* Find the innermost pending block that contains the label. (Check containment by comparing insn-uids.) Then restore the outermost stack level within that block, and do cleanups of all blocks contained in it. */ for (block = block_stack; block; block = block->next) { if (INSN_UID (block->data.block.first_insn) < INSN_UID (label)) break; if (block->data.block.stack_level != 0) stack_level = block->data.block.stack_level; /* Execute the cleanups for blocks we are exiting. */ if (block->data.block.cleanups != 0) { expand_cleanups (block->data.block.cleanups, NULL_TREE, 1, 1); do_pending_stack_adjust (); } } if (stack_level) { /* Ensure stack adjust isn't done by emit_jump, as this would clobber the stack pointer. This one should be deleted as dead by flow. */ clear_pending_stack_adjust (); do_pending_stack_adjust (); emit_stack_restore (SAVE_BLOCK, stack_level, NULL_RTX);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -