?? stmt.c
字號(hào):
struct goto_fixup{ /* Points to following fixup. */ struct goto_fixup *next; /* Points to the insn before the jump insn. If more code must be inserted, it goes after this insn. */ rtx before_jump; /* The LABEL_DECL that this jump is jumping to, or 0 for break, continue or return. */ tree target; /* The CODE_LABEL rtx that this is jumping to. */ rtx target_rtl; /* Number of binding contours started in current function before the label reference. */ 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 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;};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;};/* Specify the location in the RTL code of a label BODY, 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 (body) tree body;{ struct label_chain *p; do_pending_stack_adjust (); emit_label (label_rtx (body)); 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 = body; }}/* Generate RTL code for a `goto' statement with target label BODY. BODY should be a LABEL_DECL tree node that was or will later be defined with `expand_label'. */voidexpand_goto (body) tree body;{ expand_goto_internal (body, label_rtx (body), 0);}/* 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; 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, 0); } if (stack_level) emit_move_insn (stack_pointer_rtx, stack_level); if (body != 0 && TREE_PACKED (body)) error ("jump to `%s' invalidly jumps into binding contour", IDENTIFIER_POINTER (DECL_NAME (body))); } /* Label not yet defined: may need to put this goto on the fixup list. */ else if (! expand_fixup (body, label, last_insn)) { /* No fixup needed. Record that the label is the target of at least one goto that has no fixup. */ if (body != 0) TREE_ADDRESSABLE (body) = 1; } emit_jump (label);}/* Generate if necessary a fixup for a goto whose target label in tree structure (if any) is TREE_LABEL and whose target in rtl is RTL_LABEL. If LAST_INSN is nonzero, we pretend that the jump appears after insn LAST_INSN instead of at the current point in the insn stream. The fixup will be used later to insert insns at this point to restore the stack level as appropriate for the target label. Value is nonzero if a fixup is made. */static intexpand_fixup (tree_label, rtl_label, last_insn) tree tree_label; rtx rtl_label; rtx last_insn;{ struct nesting *block, *end_block; /* See if we can recognize which block the label will be output in. This is possible in some very common cases. If we succeed, set END_BLOCK to that block. Otherwise, set it to 0. */ if (cond_stack && (rtl_label == cond_stack->data.cond.else_label || rtl_label == cond_stack->data.cond.after_label)) end_block = cond_stack; /* If we are in a loop, recognize certain labels which are likely targets. This reduces the number of fixups we need to create. */ else if (loop_stack && (rtl_label == loop_stack->data.loop.start_label || rtl_label == loop_stack->data.loop.end_label || rtl_label == loop_stack->data.loop.continue_label)) end_block = loop_stack; else end_block = 0; /* Now set END_BLOCK to the binding level to which we will return. */ if (end_block) { struct nesting *next_block = end_block->all; block = block_stack; /* First see if the END_BLOCK is inside the innermost binding level. If so, then no cleanups or stack levels are relevant. */ while (next_block && next_block != block) next_block = next_block->all; if (next_block) return 0; /* Otherwise, set END_BLOCK to the innermost binding level which is outside the relevant control-structure nesting. */ next_block = block_stack->next; for (block = block_stack; block != end_block; block = block->all) if (block == next_block) next_block = next_block->next; end_block = next_block; } /* Does any containing block have a stack level or cleanups? If not, no fixup is needed, and that is the normal case (the only case, for standard C). */ for (block = block_stack; block != end_block; block = block->next) if (block->data.block.stack_level != 0 || block->data.block.cleanups != 0) break; if (block != end_block) { /* Ok, a fixup is needed. Add a fixup to the list of such. */ struct goto_fixup *fixup = (struct goto_fixup *) oballoc (sizeof (struct goto_fixup)); /* In case an old stack level is restored, make sure that comes after any pending stack adjust. */ do_pending_stack_adjust (); fixup->before_jump = last_insn ? last_insn : get_last_insn (); fixup->target = tree_label; fixup->target_rtl = rtl_label; fixup->block_start_count = block_start_count; fixup->stack_level = 0; fixup->cleanup_list_list = (block->data.block.outer_cleanups || block->data.block.cleanups ? tree_cons (0, block->data.block.cleanups, block->data.block.outer_cleanups) : 0); fixup->next = goto_fixup_chain; goto_fixup_chain = fixup; } return block != 0;}/* When exiting a binding contour, process all pending gotos requiring fixups. THISBLOCK is the structure that describes the block being exited. STACK_LEVEL is the rtx for the stack level to restore exiting this contour. CLEANUP_LIST is a list of expressions to evaluate on exiting this contour. FIRST_INSN is the insn that began this contour. Gotos that jump out of this contour must restore the stack level and do the cleanups before actually jumping. DONT_JUMP_IN nonzero means report error there is a jump into this contour from before the beginning of the contour. This is also done if STACK_LEVEL is nonzero. */static voidfixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in) struct nesting *thisblock; rtx stack_level; tree cleanup_list; rtx first_insn; int dont_jump_in;{ register struct goto_fixup *f, *prev; /* F is the fixup we are considering; PREV is the previous one. */ for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next) { /* Test for a fixup that is inactive because it is already handled. */ if (f->before_jump == 0) { /* Delete inactive fixup from the chain, if that is easy to do. */ if (prev != 0) prev->next = f->next; } /* Has this fixup's target label been defined? If so, we can finalize it. */ else if (PREV_INSN (f->target_rtl) != 0) { rtx after_label = f->target_rtl; while (after_label != 0 && GET_CODE (after_label) == CODE_LABEL) after_label = NEXT_INSN (after_label); /* If this fixup jumped into this contour from before the beginning of this contour, report an error. */ /* ??? Bug: this does not detect jumping in through intermediate blocks that have stack levels or cleanups. It detects only a problem with the innermost block around the label. */ if (f->target != 0 && (dont_jump_in || stack_level || cleanup_list) /* If AFTER_LABEL is 0, it means the jump goes to the end of the rtl, which means it jumps into this scope. */ && (after_label == 0 || INSN_UID (first_insn) < INSN_UID (after_label)) && INSN_UID (first_insn) > INSN_UID (f->before_jump) && ! TREE_REGDECL (f->target)) { error_with_decl (f->target, "label `%s' used before containing binding contour"); /* Prevent multiple errors for one label. */ TREE_REGDECL (f->target) = 1; } /* Execute cleanups for blocks this jump exits. */ if (f->cleanup_list_list) { tree lists; for (lists = f->cleanup_list_list; lists; lists = TREE_CHAIN (lists)) /* Marked elements correspond to blocks that have been closed. Do their cleanups. */ if (TREE_ADDRESSABLE (lists) && TREE_VALUE (lists) != 0) fixup_cleanups (TREE_VALUE (lists), &f->before_jump); } /* Restore stack level for the biggest contour that this jump jumps out of. */ if (f->stack_level) emit_insn_after (gen_move_insn (stack_pointer_rtx, f->stack_level), f->before_jump); f->before_jump = 0; } /* Label has still not appeared. If we are exiting a block with a stack level to restore, that started before the fixup, mark this stack level as needing restoration when the fixup is later finalized. Also mark the cleanup_list_list element for F that corresponds to this block, so that ultimately this block's cleanups will be executed by the code above. */ /* Note: if THISBLOCK == 0 and we have a label that hasn't appeared, it means the label is undefined. That's erroneous, but possible. */ else if (thisblock != 0 && (thisblock->data.block.block_start_count < f->block_start_count)) { tree lists = f->cleanup_list_list; for (; lists; lists = TREE_CHAIN (lists)) /* If the following elt. corresponds to our containing block then the elt. must be for this block. */ if (TREE_CHAIN (lists) == thisblock->data.block.outer_cleanups) TREE_ADDRESSABLE (lists) = 1; if (stack_level) f->stack_level = stack_level; } }}/* Generate RTL for an asm statement (explicit assembler code). BODY is a STRING_CST node containing the assembler code text. */voidexpand_asm (body) tree body;{ emit_insn (gen_rtx (ASM_INPUT, VOIDmode, TREE_STRING_POINTER (body))); last_expr_type = 0;}/* Generate RTL for an asm statement with arguments. STRING is the instruction template. OUTPUTS is a list of output arguments (lvalues); INPUTS a list of inputs. Each output or input has an expression in the TREE_VALUE and a constraint-string in the TREE_PURPOSE. CLOBBERS is a list of STRING_CST nodes each naming a hard register that is clobbered by this insn. Not all kinds of lvalue that may appear in OUTPUTS can be stored directly. Some elements of OUTPUTS may be replaced with trees representing temporary values. The caller should copy those temporary values to the originally specified lvalues. VOL nonzero means the insn is volatile; don't optimize it. */voidexpand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) tree string, outputs, inputs, clobbers; int vol; char *filename; int line;{ rtvec argvec, constraints; rtx body; int ninputs = list_length (inputs); int noutputs = list_length (outputs); int nclobbers = list_length (clobbers); tree tail; register int i; /* Vector of RTX's of evaluated output operands. */ rtx *output_rtx = (rtx *) alloca (noutputs * sizeof (rtx)); /* The insn we have emitted. */ rtx insn; last_expr_type = 0; for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) { tree val = TREE_VALUE (tail); tree val1; int j; int found_equal; /* If there's an erroneous arg, emit no insn. */ if (TREE_TYPE (val) == error_mark_node) return; /* Make sure constraint has `=' and does not have `+'. */ found_equal = 0; for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)); j++) { if (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] == '+') { error ("output operand constraint contains `+'"); return; } if (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] == '=') found_equal = 1; } if (! found_equal)
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -