📄 stmt.c
字号:
Make an entry on loop_stack to record the labels associated with this loop. */voidexpand_start_loop (exit_flag) int exit_flag;{ register struct nesting *thisloop = (struct nesting *) xmalloc (sizeof (struct nesting)); /* Make an entry on loop_stack for the loop we are entering. */ thisloop->next = loop_stack; thisloop->all = nesting_stack; thisloop->depth = ++nesting_depth; thisloop->data.loop.start_label = gen_label_rtx (); thisloop->data.loop.end_label = gen_label_rtx (); thisloop->data.loop.continue_label = thisloop->data.loop.start_label; thisloop->exit_label = exit_flag ? thisloop->data.loop.end_label : 0; loop_stack = thisloop; nesting_stack = thisloop; do_pending_stack_adjust (); emit_queue (); emit_note (0, NOTE_INSN_LOOP_BEG); emit_label (thisloop->data.loop.start_label);}/* Like expand_start_loop but for a loop where the continuation point (for expand_continue_loop) will be specified explicitly. */voidexpand_start_loop_continue_elsewhere (exit_flag) int exit_flag;{ expand_start_loop (exit_flag); loop_stack->data.loop.continue_label = gen_label_rtx ();}/* Specify the continuation point for a loop started with expand_start_loop_continue_elsewhere. Use this at the point in the code to which a continue statement should jump. */voidexpand_loop_continue_here (){ do_pending_stack_adjust (); emit_note (0, NOTE_INSN_LOOP_CONT); emit_label (loop_stack->data.loop.continue_label);}/* Finish a loop. Generate a jump back to the top and the loop-exit label. Pop the block off of loop_stack. */voidexpand_end_loop (){ register rtx insn = get_last_insn (); register rtx start_label = loop_stack->data.loop.start_label; do_pending_stack_adjust (); while (insn && GET_CODE (insn) == NOTE) insn = PREV_INSN (insn); /* If optimizing, perhaps reorder the loop. If the loop does not already end with a conditional branch, scan over the insns within the loop and try to find a conditional branch which is a loop exit. If such an insn is found, move that insn (and its predecessors) to the end of the loop so that the conditional exit and the jump back can perhaps be optimized into one insn. */ if (optimize && insn != 0 && ! (GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) == SET && SET_DEST (PATTERN (insn)) == pc_rtx && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE)) { /* Scan insns from the top of the loop looking for a qualified conditional exit. */ for (insn = loop_stack->data.loop.start_label; insn; insn= NEXT_INSN (insn)) if (GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) == SET && SET_DEST (PATTERN (insn)) == pc_rtx && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE && ((GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == LABEL_REF && (XEXP (XEXP (SET_SRC (PATTERN (insn)), 1), 0) == loop_stack->data.loop.end_label)) || (GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 2)) == LABEL_REF && (XEXP (XEXP (SET_SRC (PATTERN (insn)), 2), 0) == loop_stack->data.loop.end_label)))) break; if (insn != 0) { /* We found one. Move everything from there up to the end of the loop, and add a jump into the loop to jump to there. */ register rtx newstart_label = gen_label_rtx (); emit_label_after (newstart_label, PREV_INSN (start_label)); reorder_insns (start_label, insn, get_last_insn ()); emit_jump_insn_after (gen_jump (start_label), PREV_INSN (newstart_label)); emit_barrier_after (PREV_INSN (newstart_label)); start_label = newstart_label; } } emit_jump (start_label); emit_note (0, NOTE_INSN_LOOP_END); emit_label (loop_stack->data.loop.end_label); POPSTACK (loop_stack); last_expr_type = 0;}/* Generate a jump to the current loop's continue-point. This is usually the top of the loop, but may be specified explicitly elsewhere. If not currently inside a loop, return 0 and do nothing; caller will print an error message. */intexpand_continue_loop (){ last_expr_type = 0; if (loop_stack == 0) return 0; expand_goto_internal (0, loop_stack->data.loop.continue_label, 0); return 1;}/* Generate a jump to exit the current loop. If not currently inside a loop, return 0 and do nothing; caller will print an error message. */intexpand_exit_loop (){ last_expr_type = 0; if (loop_stack == 0) return 0; expand_goto_internal (0, loop_stack->data.loop.end_label, 0); return 1;}/* Generate a conditional jump to exit the current loop if COND evaluates to zero. If not currently inside a loop, return 0 and do nothing; caller will print an error message. */intexpand_exit_loop_if_false (cond) tree cond;{ last_expr_type = 0; if (loop_stack == 0) return 0; do_jump (cond, loop_stack->data.loop.end_label, NULL); return 1;}/* Return non-zero if currently inside a loop. */intinside_loop (){ return loop_stack != 0;}/* Generate a jump to exit the current loop, conditional, binding contour or case statement. Not all such constructs are visible to this function, only those started with EXIT_FLAG nonzero. Individual languages use the EXIT_FLAG parameter to control which kinds of constructs you can exit this way. If not currently inside anything that can be exited, return 0 and do nothing; caller will print an error message. */intexpand_exit_something (){ struct nesting *n; last_expr_type = 0; for (n = nesting_stack; n; n = n->all) if (n->exit_label != 0) { expand_goto_internal (0, n->exit_label, 0); return 1; } return 0;}/* Generate RTL to return from the current function, with no value. (That is, we do not do anything about returning any value.) */voidexpand_null_return (){ struct nesting *block = block_stack; rtx last_insn = 0; /* Does any pending block have cleanups? */ while (block && block->data.block.cleanups == 0) block = block->next; /* If yes, use a goto to return, since that runs cleanups. */ expand_null_return_1 (last_insn, block != 0);}/* Output a return with no value. If LAST_INSN is nonzero, pretend that the return takes place after LAST_INSN. If USE_GOTO is nonzero then don't use a return instruction; go to the return label instead. This causes any cleanups of pending blocks to be executed normally. */static voidexpand_null_return_1 (last_insn, use_goto) rtx last_insn; int use_goto;{ rtx end_label = cleanup_label ? cleanup_label : return_label; clear_pending_stack_adjust (); do_pending_stack_adjust (); last_expr_type = 0; /* PCC-struct return always uses an epilogue. */ if (current_function_returns_pcc_struct || use_goto) { if (end_label == 0) end_label = return_label = gen_label_rtx (); expand_goto_internal (0, end_label, last_insn); return; } /* Otherwise output a simple return-insn if one is available, unless it won't do the job. */#ifdef HAVE_return if (HAVE_return && cleanup_label == 0) { emit_jump_insn (gen_return ()); emit_barrier (); return; }#endif /* Otherwise jump to the epilogue. */ expand_goto_internal (0, end_label, last_insn);}/* Generate RTL to evaluate the expression RETVAL and return it from the current function. */voidexpand_return (retval) tree retval;{ /* If there are any cleanups to be performed, then they will be inserted following LAST_INSN. It is desirable that the last_insn, for such purposes, should be the last insn before computing the return value. Otherwise, cleanups which call functions can clobber the return value. */ /* ??? rms: I think that is erroneous, because in C++ it would run destructors on variables that might be used in the subsequent computation of the return value. */ rtx last_insn = 0; register rtx val = 0; register rtx op0; tree retval_rhs; int cleanups; struct nesting *block; /* Are any cleanups needed? E.g. C++ destructors to be run? */ cleanups = 0; for (block = block_stack; block; block = block->next) if (block->data.block.cleanups != 0) { cleanups = 1; break; } if (TREE_CODE (retval) == RESULT_DECL) retval_rhs = retval; else if ((TREE_CODE (retval) == MODIFY_EXPR || TREE_CODE (retval) == INIT_EXPR) && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL) retval_rhs = TREE_OPERAND (retval, 1); else if (TREE_TYPE (retval) == void_type_node) /* Recognize tail-recursive call to void function. */ retval_rhs = retval; else retval_rhs = NULL_TREE; /* Only use `last_insn' if there are cleanups which must be run. */ if (cleanups || cleanup_label != 0) last_insn = get_last_insn (); /* For tail-recursive call to current function, just jump back to the beginning. It's unsafe if any auto variable in this function has its address taken; for simplicity, require stack frame to be empty. */ if (optimize && retval_rhs != 0 && frame_offset == STARTING_FRAME_OFFSET && TREE_CODE (retval_rhs) == CALL_EXPR && TREE_CODE (TREE_OPERAND (retval_rhs, 0)) == ADDR_EXPR && TREE_OPERAND (TREE_OPERAND (retval_rhs, 0), 0) == this_function /* Finish checking validity, and if valid emit code to set the argument variables for the new call. */ && tail_recursion_args (TREE_OPERAND (retval_rhs, 1), DECL_ARGUMENTS (this_function))) { if (tail_recursion_label == 0) { tail_recursion_label = gen_label_rtx (); emit_label_after (tail_recursion_label, tail_recursion_reentry); } emit_queue (); expand_goto_internal (0, tail_recursion_label, last_insn); emit_barrier (); return; }#ifdef HAVE_return /* This optimization is safe if there are local cleanups because expand_null_return takes care of them. ??? I think it should also be safe when there is a cleanup label, because expand_null_return takes care of them, too. Any reason why not? */ if (HAVE_return && cleanup_label == 0 && ! current_function_returns_pcc_struct) { /* If this is return x == y; then generate if (x == y) return 1; else return 0; if we can do it with explicit return insns. */ if (retval_rhs) switch (TREE_CODE (retval_rhs)) { case EQ_EXPR: case NE_EXPR: case GT_EXPR: case GE_EXPR: case LT_EXPR: case LE_EXPR: case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case TRUTH_AND_EXPR: case TRUTH_OR_EXPR: case TRUTH_NOT_EXPR: op0 = gen_label_rtx (); val = DECL_RTL (DECL_RESULT (this_function)); jumpifnot (retval_rhs, op0); emit_move_insn (val, const1_rtx); emit_insn (gen_rtx (USE, VOIDmode, val)); expand_null_return (); emit_label (op0); emit_move_insn (val, const0_rtx); emit_insn (gen_rtx (USE, VOIDmode, val)); expand_null_return (); return; } }#endif /* HAVE_return */ if (cleanups && retval_rhs != 0 && TREE_TYPE (retval_rhs) != void_type_node && GET_CODE (DECL_RTL (DECL_RESULT (this_function))) == REG) { rtx last_insn; /* Calculate the return value into a pseudo reg. */ val = expand_expr (retval_rhs, 0, VOIDmode, 0); emit_queue (); /* Put the cleanups here. */ last_insn = get_last_insn (); /* Copy the value into hard return reg. */ emit_move_insn (DECL_RTL (DECL_RESULT (this_function)), val); val = DECL_RTL (DECL_RESULT (this_function)); if (GET_CODE (val) == REG) emit_insn (gen_rtx (USE, VOIDmode, val)); expand_null_return_1 (last_insn, cleanups); } else { /* No cleanups or no hard reg used; calculate value into hard return reg and let cleanups come after. */ val = expand_expr (retval, 0, VOIDmode, 0); emit_queue (); val = DECL_RTL (DECL_RESULT (this_function)); if (val && GET_CODE (val) == REG) emit_insn (gen_rtx (USE, VOIDmode, val)); expand_null_return (); }}/* Return 1 if the end of the generated RTX is not a barrier. This means code already compiled can drop through. */intdrop_through_at_end_p (){ rtx insn = get_last_insn (); while (insn && GET_CODE (insn) == NOTE) insn = PREV_INSN (insn); return insn && GET_CODE (insn) != BARRIER;}/* Emit code to alter this function's formal parms for a tail-recursive call.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -