📄 stmt.c
字号:
/* Expands front end tree to back end RTL for GNU C-Compiler Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. *//* This file handles the generation of rtl code from tree structure above the level of expressions, using subroutines in exp*.c and emit-rtl.c. It also creates the rtl expressions for parameters and auto variables and has full responsibility for allocating stack slots. The functions whose names start with `expand_' are called by the parser to generate RTL instructions for various kinds of constructs. Some control and binding constructs require calling several such functions at different times. For example, a simple if-then is expanded by calling `expand_start_cond' (with the condition-expression as argument) before parsing the then-clause and calling `expand_end_cond' after parsing the then-clause. */#include "config.h"#include <stdio.h>#include <ctype.h>#include "rtl.h"#include "tree.h"#include "flags.h"#include "function.h"#include "insn-flags.h"#include "insn-config.h"#include "insn-codes.h"#include "expr.h"#include "hard-reg-set.h"#include "obstack.h"#include "loop.h"#include "recog.h"#define obstack_chunk_alloc xmalloc#define obstack_chunk_free freestruct obstack stmt_obstack;/* Filename and line number of last line-number note, whether we actually emitted it or not. */char *emit_filename;int emit_lineno;/* Nonzero if within a ({...}) grouping, in which case we must always compute a value for each expr-stmt in case it is the last one. */int expr_stmts_for_value;/* Each time we expand an expression-statement, record the expr's type and its RTL value here. */static tree last_expr_type;static rtx last_expr_value;/* Each time we expand the end of a binding contour (in `expand_end_bindings') and we emit a new NOTE_INSN_BLOCK_END note, we save a pointer to it here. This is used by the `remember_end_note' function to record the endpoint of each generated block in its associated BLOCK node. */static rtx last_block_end_note;/* Number of binding contours started so far in this function. */int block_start_count;/* Nonzero if function being compiled needs to return the address of where it has put a structure value. */extern int current_function_returns_pcc_struct;/* Label that will go on parm cleanup code, if any. Jumping to this label runs cleanup code for parameters, if such code must be run. Following this code is the logical return label. */extern rtx cleanup_label;/* Label that will go on function epilogue. Jumping to this label serves as a "return" instruction on machines which require execution of the epilogue on all returns. */extern rtx return_label;/* List (chain of EXPR_LISTs) of pseudo-regs of SAVE_EXPRs. So we can mark them all live at the end of the function, if nonopt. */extern rtx save_expr_regs;/* Offset to end of allocated area of stack frame. If stack grows down, this is the address of the last stack slot allocated. If stack grows up, this is the address for the next slot. */extern int frame_offset;/* Label to jump back to for tail recursion, or 0 if we have not yet needed one for this function. */extern rtx tail_recursion_label;/* Place after which to insert the tail_recursion_label if we need one. */extern rtx tail_recursion_reentry;/* Location at which to save the argument pointer if it will need to be referenced. There are two cases where this is done: if nonlocal gotos exist, or if vars whose is an offset from the argument pointer will be needed by inner routines. */extern rtx arg_pointer_save_area;/* Chain of all RTL_EXPRs that have insns in them. */extern tree rtl_expr_chain;#if 0 /* Turned off because 0 seems to work just as well. *//* Cleanup lists are required for binding levels regardless of whether that binding level has cleanups or not. This node serves as the cleanup list whenever an empty list is required. */static tree empty_cleanup_list;#endif/* Functions and data structures for expanding case statements. *//* Case label structure, used to hold info on labels within case statements. We handle "range" labels; for a single-value label as in C, the high and low limits are the same. A chain of case nodes is initially maintained via the RIGHT fields in the nodes. Nodes with higher case values are later in the list. Switch statements can be output in one of two forms. A branch table is used if there are more than a few labels and the labels are dense within the range between the smallest and largest case value. If a branch table is used, no further manipulations are done with the case node chain. The alternative to the use of a branch table is to generate a series of compare and jump insns. When that is done, we use the LEFT, RIGHT, and PARENT fields to hold a binary tree. Initially the tree is totally unbalanced, with everything on the right. We balance the tree with nodes on the left having lower case values than the parent and nodes on the right having higher values. We then output the tree in order. */struct case_node{ struct case_node *left; /* Left son in binary tree */ struct case_node *right; /* Right son in binary tree; also node chain */ struct case_node *parent; /* Parent of node in binary tree */ tree low; /* Lowest index value for this label */ tree high; /* Highest index value for this label */ tree code_label; /* Label to jump to when node matches */};typedef struct case_node case_node;typedef struct case_node *case_node_ptr;/* These are used by estimate_case_costs and balance_case_nodes. *//* This must be a signed type, and non-ANSI compilers lack signed char. */static short *cost_table;static int use_cost_table;static int estimate_case_costs ();static void balance_case_nodes ();static void emit_case_nodes ();static void group_case_nodes ();static void emit_jump_if_reachable ();static int warn_if_unused_value ();static void expand_goto_internal ();static int expand_fixup ();void fixup_gotos ();void free_temp_slots ();static void expand_cleanups ();static void expand_null_return_1 ();static int tail_recursion_args ();static void do_jump_if_equal ();/* Stack of control and binding constructs we are currently inside. These constructs begin when you call `expand_start_WHATEVER' and end when you call `expand_end_WHATEVER'. This stack records info about how the construct began that tells the end-function what to do. It also may provide information about the construct to alter the behavior of other constructs within the body. For example, they may affect the behavior of C `break' and `continue'. Each construct gets one `struct nesting' object. All of these objects are chained through the `all' field. `nesting_stack' points to the first object (innermost construct). The position of an entry on `nesting_stack' is in its `depth' field. Each type of construct has its own individual stack. For example, loops have `loop_stack'. Each object points to the next object of the same type through the `next' field. Some constructs are visible to `break' exit-statements and others are not. Which constructs are visible depends on the language. Therefore, the data structure allows each construct to be visible or not, according to the args given when the construct is started. The construct is visible if the `exit_label' field is non-null. In that case, the value should be a CODE_LABEL rtx. */struct nesting{ struct nesting *all; struct nesting *next; int depth; rtx exit_label; union { /* For conds (if-then and if-then-else statements). */ struct { /* Label for the end of the if construct. There is none if EXITFLAG was not set and no `else' has been seen yet. */ rtx endif_label; /* Label for the end of this alternative. This may be the end of the if or the next else/elseif. */ rtx next_label; } cond; /* For loops. */ struct { /* Label at the top of the loop; place to loop back to. */ rtx start_label; /* Label at the end of the whole construct. */ rtx end_label; /* Label for `continue' statement to jump to; this is in front of the stepper of the loop. */ rtx continue_label; } loop; /* For variable binding contours. */ struct { /* Sequence number of this binding contour within the function, in order of entry. */ int block_start_count; /* Nonzero => value to restore stack to on exit. */ rtx stack_level; /* The NOTE that starts this contour. Used by expand_goto to check whether the destination is within each contour or not. */ rtx first_insn; /* Innermost containing binding contour that has a stack level. */ struct nesting *innermost_stack_block; /* List of cleanups to be run on exit from this contour. This is a list of expressions to be evaluated. The TREE_PURPOSE of each link is the ..._DECL node which the cleanup pertains to. */ tree cleanups; /* List of cleanup-lists of blocks containing this block, as they were at the locus where this block appears. There is an element for each containing block, ordered innermost containing block first. The tail of this list can be 0 (was empty_cleanup_list), if all remaining elements would be empty lists. The element's TREE_VALUE is the cleanup-list of that block, which may be null. */ tree outer_cleanups; /* Chain of labels defined inside this binding contour. For contours that have stack levels or cleanups. */ struct label_chain *label_chain; /* Number of function calls seen, as of start of this block. */ int function_call_count; } block; /* For switch (C) or case (Pascal) statements, and also for dummies (see `expand_start_case_dummy'). */ struct { /* The insn after which the case dispatch should finally be emitted. Zero for a dummy. */ rtx start; /* A list of case labels, kept in ascending order by value as the list is built. During expand_end_case, this list may be rearranged into a nearly balanced binary tree. */ struct case_node *case_list; /* Label to jump to if no case matches. */ tree default_label; /* The expression to be dispatched on. */ tree index_expr; /* Type that INDEX_EXPR should be converted to. */ tree nominal_type; /* Number of range exprs in case statement. */ int num_ranges; /* Name of this kind of statement, for warnings. */ char *printname; /* Nonzero if a case label has been seen in this case stmt. */ char seenlabel; } case_stmt; /* For exception contours. */ struct { /* List of exceptions raised. This is a TREE_LIST of whatever you want. */ tree raised; /* List of exceptions caught. This is also a TREE_LIST of whatever you want. As a special case, it has the value `void_type_node' if it handles default exceptions. */ tree handled; /* First insn of TRY block, in case resumptive model is needed. */ rtx first_insn; /* Label for the catch clauses. */ rtx except_label; /* Label for unhandled exceptions. */ rtx unhandled_label; /* Label at the end of whole construct. */ rtx after_label; /* Label which "escapes" the exception construct. Like EXIT_LABEL for BREAK construct, but for exceptions. */ rtx escape_label; } except_stmt; } data;};/* Chain of all pending binding contours. */struct nesting *block_stack;/* If any new stacks are added here, add them to POPSTACKS too. *//* Chain of all pending binding contours that restore stack levels or have cleanups. */struct nesting *stack_block_stack;/* Chain of all pending conditional statements. */struct nesting *cond_stack;/* Chain of all pending loops. */struct nesting *loop_stack;/* Chain of all pending case or switch statements. */struct nesting *case_stack;/* Chain of all pending exception contours. */struct nesting *except_stack;/* Separate chain including all of the above, chained through the `all' field. */struct nesting *nesting_stack;/* Number of entries on nesting_stack now. */int nesting_depth;/* Allocate and return a new `struct nesting'. */#define ALLOC_NESTING() \ (struct nesting *) obstack_alloc (&stmt_obstack, sizeof (struct nesting))/* Pop the nesting stack element by element until we pop off the element which is at the top of STACK. Update all the other stacks, popping off elements from them as we pop them from nesting_stack. */#define POPSTACK(STACK) \do { struct nesting *target = STACK; \ struct nesting *this; \ do { this = nesting_stack; \ if (loop_stack == this) \ loop_stack = loop_stack->next; \ if (cond_stack == this) \ cond_stack = cond_stack->next; \ if (block_stack == this) \ block_stack = block_stack->next; \ if (stack_block_stack == this) \ stack_block_stack = stack_block_stack->next; \ if (case_stack == this) \ case_stack = case_stack->next; \ if (except_stack == this) \ except_stack = except_stack->next; \ nesting_depth = nesting_stack->depth - 1; \ nesting_stack = this->all; \ obstack_free (&stmt_obstack, this); } \ while (this != target); } while (0)/* In some cases it is impossible to generate code for a forward goto until the label definition is seen. This happens when it may be necessary for the goto to reset the stack pointer: we don't yet know how to do that. So expand_goto puts an entry on this fixup list. Each time a binding contour that resets the stack is exited, we check each fixup. If the target label has now been defined, we can insert the proper code. */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 BLOCK for the place where this goto was found. */ tree context; /* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -