📄 stmt.c
字号:
/* Expands front end tree to back end RTL for GNU C-Compiler Copyright (C) 1987, 1988, 1989 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 1, 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. `expand_function_start' is called at the beginning of a function, before the function body is parsed, and `expand_function_end' is called after parsing the body. Call `assign_stack_local' to allocate a stack slot for a local variable. This is usually done during the RTL generation for the function body, but it can also be done in the reload pass when a pseudo-register does not get a hard register. Call `put_var_into_stack' when you learn, belatedly, that a variable previously given a pseudo-register must in fact go in the stack. This function changes the DECL_RTL to be a stack slot instead of a reg then scans all the RTL instructions so far generated to correct them. */#include "config.h"#include <stdio.h>#include "rtl.h"#include "tree.h"#include "flags.h"#include "insn-flags.h"#include "insn-config.h"#include "insn-codes.h"#include "expr.h"#include "regs.h"#include "hard-reg-set.h"#include "recog.h"#define MAX(x,y) (((x) > (y)) ? (x) : (y))#define MIN(x,y) (((x) < (y)) ? (x) : (y))/* Nonzero if function being compiled pops its args on return. May affect compilation of return insn or of function epilogue. */int current_function_pops_args;/* Nonzero if function being compiled needs to be given an address where the value should be stored. */int current_function_returns_struct;/* Nonzero if function being compiled needs to return the address of where it has put a structure value. */int current_function_returns_pcc_struct;/* Nonzero if function being compiled needs to be passed a static chain. */int current_function_needs_context;/* Nonzero if function being compiled can call setjmp. */int current_function_calls_setjmp;/* Nonzero if function being compiled can call alloca, either as a subroutine or builtin. */int current_function_calls_alloca;/* Nonzero if the current function returns a pointer type */int current_function_returns_pointer;/* If function's args have a fixed size, this is that size, in bytes. Otherwise, it is -1. May affect compilation of return insn or of function epilogue. */int current_function_args_size;/* # bytes the prologue should push and pretend that the caller pushed them. The prologue must do this, but only if parms can be passed in registers. */int current_function_pretend_args_size;/* This is the offset from the arg pointer to the place where the first anonymous arg can be found, if there is one. */rtx current_function_arg_offset_rtx;/* Name of function now being compiled. */char *current_function_name;/* 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. */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. */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. */rtx save_expr_regs;/* List (chain of EXPR_LISTs) of all stack slots in this function. Made for the sake of unshare_all_rtl. */rtx stack_slot_list;/* Filename and line number of last line-number note, whether we actually emitted it or not. */char *emit_filename;int emit_lineno;/* Insn after which register parms and SAVE_EXPRs are born, if nonopt. */static rtx parm_birth_insn;/* The FUNCTION_DECL node for the function being compiled. */static tree this_function;/* Number of binding contours started so far in this function. */static int block_start_count;/* 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. */int frame_offset;/* Nonzero if a stack slot has been generated whose address is not actually valid. It means that the generated rtl must all be scanned to detect and correct the invalid addresses where they occur. */static int invalid_stack_slot;/* Label to jump back to for tail recursion, or 0 if we have not yet needed one for this function. */static rtx tail_recursion_label;/* Place after which to insert the tail_recursion_label if we need one. */static rtx tail_recursion_reentry;/* 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;/* Chain of all RTL_EXPRs that have insns in them. */static tree rtl_expr_chain;/* Last insn of those whose job was to put parms into their nominal homes. */static rtx last_parm_insn;/* 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. */struct case_node{ struct case_node *left; struct case_node *right; struct case_node *parent; tree low; tree high; tree test_label; tree code_label;};typedef struct case_node case_node;typedef struct case_node *case_node_ptr;static void balance_case_nodes ();static void emit_case_nodes ();static void group_case_nodes ();static void emit_jump_if_reachable ();/* 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 on the else-part, if any, else 0. */ rtx else_label; /* Label at the end of the whole construct. */ rtx after_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 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; } 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. */ short num_ranges; } case_stmt; } data;};/* Chain of all pending binding contours. */struct nesting *block_stack;/* 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;/* 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;/* Pop one of the sub-stacks, such as `loop_stack' or `cond_stack'; and pop off `nesting_stack' down to the same level. */#define POPSTACK(STACK) \do { int initial_depth = nesting_stack->depth; \ do { struct nesting *this = STACK; \ STACK = this->next; \ nesting_stack = this->all; \ nesting_depth = this->depth; \ free (this); } \ while (nesting_depth > initial_depth); } while (0)static int warn_if_unused_value ();static void expand_goto_internal ();static int expand_fixup ();static void fixup_gotos ();static void expand_cleanups ();static void fixup_cleanups ();static void expand_null_return_1 ();static int tail_recursion_args ();static void fixup_stack_slots ();static rtx fixup_stack_1 ();static rtx fixup_memory_subreg ();static rtx walk_fixup_memory_subreg ();static void fixup_var_refs ();static void fixup_var_refs_insns ();static rtx fixup_var_refs_1 ();static rtx parm_stack_loc ();static void optimize_bit_field ();static void do_jump_if_equal ();/* Emit a no-op instruction. */rtxemit_nop (){ rtx last_insn = get_last_insn (); if (!optimize && (GET_CODE (last_insn) == CODE_LABEL || prev_real_insn (last_insn) == 0)) emit_insn (gen_nop ());}/* Return the rtx-label that corresponds to a LABEL_DECL, creating it if necessary. */static 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 ();}/* Handle goto statements and the labels that they can go to. *//* 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. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -