📄 stmt.c
字号:
{ /* 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. */ /* ?? If the fixup isn't to come at the present position, doing the stack adjust here isn't useful. Doing it with our settings at that location isn't useful either. Let's hope someone does it! */ if (last_insn == 0) do_pending_stack_adjust (); fixup->target = tree_label; fixup->target_rtl = rtl_label; /* Create a BLOCK node and a corresponding matched set of NOTE_INSN_BEGIN_BLOCK and NOTE_INSN_END_BLOCK notes at this point. The notes will encapsulate any and all fixup code which we might later insert at this point in the insn stream. Also, the BLOCK node will be the parent (i.e. the `SUPERBLOCK') of any other BLOCK nodes which we might create later on when we are expanding the fixup code. */ { register rtx original_before_jump = last_insn ? last_insn : get_last_insn (); start_sequence (); pushlevel (0); fixup->before_jump = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG); last_block_end_note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_END); fixup->context = poplevel (1, 0, 0); /* Create the BLOCK node now! */ end_sequence (); emit_insns_after (fixup->before_jump, original_before_jump); } fixup->block_start_count = block_start_count; fixup->stack_level = 0; fixup->cleanup_list_list = (((block->data.block.outer_cleanups#if 0 && block->data.block.outer_cleanups != empty_cleanup_list#endif ) || block->data.block.cleanups) ? tree_cons (NULL_TREE, 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. */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. */ /* We run this loop in two passes so that cleanups of exited blocks are run first, and blocks that are exited are marked so afterwards. */ 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) { register rtx cleanup_insns; /* Get the first non-label after the label this goto jumps to. If that's before this scope begins, we don't have a jump into the scope. */ 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) && ! DECL_REGISTER (f->target)) { error_with_decl (f->target, "label `%s' used before containing binding contour"); /* Prevent multiple errors for one label. */ DECL_REGISTER (f->target) = 1; } /* We will expand the cleanups into a sequence of their own and then later on we will attach this new sequence to the insn stream just ahead of the actual jump insn. */ start_sequence (); /* Temporarily restore the lexical context where we will logically be inserting the fixup code. We do this for the sake of getting the debugging information right. */ pushlevel (0); set_block (f->context); /* Expand the 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) { expand_cleanups (TREE_VALUE (lists), 0); /* Pop any pushes done in the cleanups, in case function is about to return. */ do_pending_stack_adjust (); } } /* Restore stack level for the biggest contour that this jump jumps out of. */ if (f->stack_level) emit_stack_restore (SAVE_BLOCK, f->stack_level, f->before_jump); /* Finish up the sequence containing the insns which implement the necessary cleanups, and then attach that whole sequence to the insn stream just ahead of the actual jump insn. Attaching it at that point insures that any cleanups which are in fact implicit C++ object destructions (which must be executed upon leaving the block) appear (to the debugger) to be taking place in an area of the generated code where the object(s) being destructed are still "in scope". */ cleanup_insns = get_insns (); poplevel (1, 0, 0); end_sequence (); emit_insns_after (cleanup_insns, f->before_jump); f->before_jump = 0; } } /* Mark the cleanups of exited blocks so that they are executed by the code above. */ for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next) if (f->before_jump != 0 && PREV_INSN (f->target_rtl) == 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. */ && thisblock != 0 /* Note: if THISBLOCK == 0 and we have a label that hasn't appeared, it means the label is undefined. That's erroneous, but possible. */ && (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, or an ADDR_EXPR containing a STRING_CST. */voidexpand_asm (body) tree body;{ if (TREE_CODE (body) == ADDR_EXPR) body = TREE_OPERAND (body, 0); 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; 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; /* Count the number of meaningful clobbered registers, ignoring what we would ignore later. */ nclobbers = 0; for (tail = clobbers; tail; tail = TREE_CHAIN (tail)) { char *regname = TREE_STRING_POINTER (TREE_VALUE (tail)); i = decode_reg_name (regname); if (i >= 0 || i == -4) ++nclobbers; } 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) { error ("output operand constraint lacks `='"); return; } /* If an output operand is not a variable or indirect ref, or a part of one, create a SAVE_EXPR which is a pseudo-reg to act as an intermediate temporary. Make the asm insn write into that, then copy it to the real output operand. */ while (TREE_CODE (val) == COMPONENT_REF || TREE_CODE (val) == ARRAY_REF) val = TREE_OPERAND (val, 0); if (TREE_CODE (val) != VAR_DECL && TREE_CODE (val) != PARM_DECL && TREE_CODE (val) != INDIRECT_REF) TREE_VALUE (tail) = save_expr (TREE_VALUE (tail)); output_rtx[i] = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0); } if (ninputs + noutputs > MAX_RECOG_OPERANDS) { error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS); return; } /* Make vectors for the expression-rtx and constraint strings. */ argvec = rtvec_alloc (ninputs); constraints = rtvec_alloc (ninputs); body = gen_rtx (ASM_OPERANDS, VOIDmode, TREE_STRING_POINTER (string), "", 0, argvec, constraints, filename, line); MEM_VOLATILE_P (body) = vol; /* Eval the inputs and put them into ARGVEC. Put their constraints into ASM_INPUTs and store in CONSTRAINTS. */ i = 0; for (tail = inputs; tail; tail = TREE_CHAIN (tail)) { int j; /* If there's an erroneous arg, emit no insn, because the ASM_INPUT would get VOIDmode and that could cause a crash in reload. */ if (TREE_TYPE (TREE_VALUE (tail)) == error_mark_node) return; if (TREE_PURPOSE (tail) == NULL_TREE) { error ("hard register `%s' listed as input operand to `asm'", TREE_STRING_POINTER (TREE_VALUE (tail)) ); return; } /* Make sure constraint has neither `=' nor `+'. */ for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)); j++) if (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] == '=' || TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] == '+') { error ("input operand constraint contains `%c'", TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]); return; } XVECEXP (body, 3, i) /* argvec */ = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0); XVECEXP (body, 4, i) /* constraints */ = gen_rtx (ASM_INPUT, TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))), TREE_STRING_POINTER (TREE_PURPOSE (tail))); i++; } /* Protect all the operands from the queue, now that they have all been evaluated. */ for (i = 0; i < ninputs; i++) XVECEXP (body, 3, i) = protect_from_queue (XVECEXP (body, 3, i), 0); for (i = 0; i < noutputs; i++) output_rtx[i] = protect_from_queue (output_rtx[i], 1); /* Now, for each output, construct an rtx (set OUTPUT (asm_operands INSN OUTPUTNUMBER OUTPUTCONSTRAINT ARGVEC CONSTRAINTS)) If there is more than one, put them inside a PARALLEL. */ if (noutputs == 1 && nclobbers == 0) { XSTR (body, 1) = TREE_STRING_POINTER (TREE_PURPOSE (outputs)); insn = emit_insn (gen_rtx (SET, VOIDmode, output_rtx[0], body)); } else if (noutputs == 0 && nclobbers == 0) { /* No output operands: put in a raw ASM_OPERANDS rtx. */ insn = emit_insn (body); } else { rtx obody = body; int num = noutputs; if (num == 0) num = 1; body = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (num + nclobbers)); /* For each output operand, store a SET. */ for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) { XVECEXP (body, 0, i) = gen_rtx (SET, VOIDmode,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -