#include "config.h"
#include "system.h"
#include "tree.h"
#include "function.h"
#include "splay-tree.h"
#include "varray.h"
#include "c-common.h"
#include "except.h"
#include "toplev.h"
#include "flags.h"
#include "ggc.h"
#include "rtl.h"
#include "expr.h"
#include "output.h"
#include "timevar.h"
#include "predict.h"
#include "feedback.h"
void (*lang_expand_stmt) PARAMS ((tree));
void (*lang_expand_decl_stmt) PARAMS ((tree));
void
begin_stmt_tree (t)
tree *t;
{
*t = build_nt (EXPR_STMT, void_zero_node);
last_tree = *t;
last_expr_type = NULL_TREE;
last_expr_filename = input_filename;
}
tree
add_stmt (t)
tree t;
{
if (input_filename != last_expr_filename)
{
int add = (strcmp (input_filename, last_expr_filename) != 0);
last_expr_filename = input_filename;
if (add)
{
tree pos = build_nt (FILE_STMT, get_identifier (input_filename));
add_stmt (pos);
}
}
TREE_CHAIN (last_tree) = t;
last_tree = t;
STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p ();
if (current_function_decl)
++DECL_NUM_STMTS (current_function_decl);
return t;
}
void
add_decl_stmt (decl)
tree decl;
{
tree decl_stmt;
decl_stmt = build_stmt (DECL_STMT, decl);
add_stmt (decl_stmt);
}
tree
add_scope_stmt (begin_p, partial_p)
int begin_p;
int partial_p;
{
tree *stack_ptr = current_scope_stmt_stack ();
tree ss;
tree top = *stack_ptr;
ss = build_stmt (SCOPE_STMT, NULL_TREE);
SCOPE_BEGIN_P (ss) = begin_p;
SCOPE_PARTIAL_P (ss) = partial_p;
if (begin_p)
{
top = tree_cons (ss, NULL_TREE, top);
*stack_ptr = top;
}
else
{
TREE_VALUE (top) = ss;
*stack_ptr = TREE_CHAIN (top);
}
add_stmt (ss);
return top;
}
void
finish_stmt_tree (t)
tree *t;
{
tree stmt;
stmt = TREE_CHAIN (*t);
*t = stmt;
last_tree = NULL_TREE;
if (cfun && stmt)
{
STMT_LINENO (stmt) = lineno;
STMT_LINENO_FOR_FN_P (stmt) = 1;
}
}
tree
build_stmt VPARAMS ((enum tree_code code, ...))
{
tree t;
int length;
int i;
VA_OPEN (p, code);
VA_FIXEDARG (p, enum tree_code, code);
t = make_node (code);
length = TREE_CODE_LENGTH (code);
STMT_LINENO (t) = lineno;
for (i = 0; i < length; i++)
TREE_OPERAND (t, i) = va_arg (p, tree);
VA_CLOSE (p);
return t;
}
tree
expand_cond (t)
tree t;
{
if (t && TREE_CODE (t) == TREE_LIST)
{
expand_stmt (TREE_PURPOSE (t));
return TREE_VALUE (t);
}
else
return t;
}
void
make_rtl_for_local_static (decl)
tree decl;
{
const char *asmspec = NULL;
if (TREE_ASM_WRITTEN (decl))
return;
if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
&& !DECL_RTL_SET_P (decl))
asmspec = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
rest_of_decl_compilation (decl, asmspec, 0, 0);
}
void
emit_local_var (decl)
tree decl;
{
if (!DECL_RTL_SET_P (decl))
{
if (DECL_C_HARD_REGISTER (decl))
rest_of_decl_compilation
(decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
0, 0);
else
expand_decl (decl);
}
if (stmts_are_full_exprs_p ())
expand_start_target_temps ();
expand_decl_init (decl);
if (stmts_are_full_exprs_p ())
expand_end_target_temps ();
}
void
genrtl_do_pushlevel ()
{
emit_line_note (input_filename, lineno);
clear_last_expr ();
}
void
genrtl_goto_stmt (destination)
tree destination;
{
if (TREE_CODE (destination) == IDENTIFIER_NODE)
abort ();
if (TREE_CODE (destination) == LABEL_DECL)
TREE_USED (destination) = 1;
emit_line_note (input_filename, lineno);
if (TREE_CODE (destination) == LABEL_DECL)
{
label_rtx (destination);
expand_goto (destination);
}
else
expand_computed_goto (destination);
}
void
genrtl_expr_stmt (expr)
tree expr;
{
genrtl_expr_stmt_value (expr, -1, 1);
}
void
genrtl_expr_stmt_value (expr, want_value, maybe_last)
tree expr;
int want_value, maybe_last;
{
if (expr != NULL_TREE)
{
emit_line_note (input_filename, lineno);
if (stmts_are_full_exprs_p ())
expand_start_target_temps ();
if (expr != error_mark_node)
expand_expr_stmt_value (expr, want_value, maybe_last);
if (stmts_are_full_exprs_p ())
expand_end_target_temps ();
}
}
void
genrtl_decl_stmt (t)
tree t;
{
tree decl;
emit_line_note (input_filename, lineno);
decl = DECL_STMT_DECL (t);
if (TREE_CODE (decl) == VAR_DECL
&& !TREE_STATIC (decl)
&& !DECL_EXTERNAL (decl))
{
if (!anon_aggr_type_p (TREE_TYPE (decl)))
emit_local_var (decl);
else
expand_anon_union_decl (decl, NULL_TREE,
DECL_ANON_UNION_ELEMS (decl));
}
else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
make_rtl_for_local_static (decl);
else if (TREE_CODE (decl) == LABEL_DECL
&& C_DECLARED_LABEL_FLAG (decl))
declare_nonlocal_label (decl);
else if (lang_expand_decl_stmt)
(*lang_expand_decl_stmt) (t);
}
void
genrtl_if_stmt (t)
tree t;
{
tree cond;
genrtl_do_pushlevel ();
cond = expand_cond (IF_COND (t));
emit_line_note (input_filename, lineno);
expand_start_cond (cond, 0);
if (THEN_CLAUSE (t))
{
emit_rtx_feedback_counter (t, 0, fdo_block);
expand_stmt (THEN_CLAUSE (t));
}
if (ELSE_CLAUSE (t))
{
emit_rtx_feedback_counter (t, 2, fdo_outgoing);
expand_start_else ();
emit_rtx_feedback_counter (t, 1, fdo_block);
expand_stmt (ELSE_CLAUSE (t));
}
expand_end_cond (t);
}
void
genrtl_while_stmt (t)
tree t;
{
tree cond;
emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop (1, t);
genrtl_do_pushlevel ();
cond = expand_cond (WHILE_COND (t));
emit_line_note (input_filename, lineno);
expand_exit_loop_top_cond (0, cond);
genrtl_do_pushlevel ();
expand_stmt (WHILE_BODY (t));
expand_end_loop ();
}
void
genrtl_do_stmt (t)
tree t;
{
tree cond = DO_COND (t);
if (!cond || integer_zerop (cond))
{
expand_start_null_loop ();
expand_stmt (DO_BODY (t));
expand_end_null_loop ();
}
else
{
emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop_continue_elsewhere (1, t);
expand_stmt (DO_BODY (t));
expand_loop_continue_here ();
cond = expand_cond (cond);
emit_line_note (input_filename, lineno);
expand_exit_loop_if_false (0, cond);
expand_end_loop ();
}
}
tree
build_return_stmt (expr)
tree expr;
{
return (build_stmt (RETURN_STMT, expr));
}
void
genrtl_return_stmt (stmt)
tree stmt;
{
tree expr;
expr = RETURN_STMT_EXPR (stmt);
emit_line_note (input_filename, lineno);
if (!expr)
{
emit_rtx_feedback_counter (stmt, 0, fdo_outgoing);
expand_null_return ();
}
else
{
expand_start_target_temps ();
emit_rtx_feedback_counter (stmt, 0, fdo_block);
expand_return (expr);
expand_end_target_temps ();
}
}
void
genrtl_for_stmt (t)
tree t;
{
tree cond;
const char *saved_filename;
int saved_lineno;
if (NEW_FOR_SCOPE_P (t))
genrtl_do_pushlevel ();
expand_stmt (FOR_INIT_STMT (t));
emit_rtx_feedback_counter (t, 3, fdo_outgoing);
emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop_continue_elsewhere (1, t);
genrtl_do_pushlevel ();
cond = expand_cond (FOR_COND (t));
saved_filename = input_filename;
saved_lineno = lineno;
emit_line_note (input_filename, lineno);
if (cond)
expand_exit_loop_top_cond (0, cond);
genrtl_do_pushlevel ();
expand_stmt (FOR_BODY (t));
emit_rtx_feedback_counter (t, 4, fdo_outgoing);
input_filename = saved_filename;
lineno = saved_lineno;
emit_line_note (input_filename, lineno);
expand_loop_continue_here ();
if (FOR_EXPR (t))
genrtl_expr_stmt (FOR_EXPR (t));
expand_end_loop ();
}
tree
build_break_stmt ()
{
return (build_stmt (BREAK_STMT));
}
void
genrtl_break_stmt (t)
tree t;
{
emit_line_note (input_filename, lineno);
if ( ! expand_exit_something (t))
error ("break statement not within loop or switch");
}
tree
build_continue_stmt ()
{
return (build_stmt (CONTINUE_STMT));
}
void
genrtl_continue_stmt (t)
tree t;
{
emit_line_note (input_filename, lineno);
emit_rtx_feedback_counter (t, 0, fdo_outgoing);
if (! expand_continue_loop (0))
error ("continue statement not within a loop");
}
void
genrtl_scope_stmt (t)
tree t;
{
tree block = SCOPE_STMT_BLOCK (t);
if (!SCOPE_NO_CLEANUPS_P (t))
{
if (SCOPE_BEGIN_P (t))
expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t), block);
else if (SCOPE_END_P (t))
expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0);
}
else if (!SCOPE_NULLIFIED_P (t))
{
rtx note = emit_note (NULL,
(SCOPE_BEGIN_P (t)
? NOTE_INSN_BLOCK_BEG
: NOTE_INSN_BLOCK_END));
NOTE_BLOCK (note) = block;
}
if (block && SCOPE_END_P (t))
{
tree fn;
for (fn = BLOCK_VARS (block); fn; fn = TREE_CHAIN (fn))
{
if (TREE_CODE (fn) == FUNCTION_DECL
&& DECL_CONTEXT (fn) == current_function_decl
&& DECL_SAVED_INSNS (fn)
&& !TREE_ASM_WRITTEN (fn)
&& TREE_ADDRESSABLE (fn))
{
push_function_context ();
output_inline_function (fn);
pop_function_context ();
}
}
}
}
void
genrtl_switch_stmt (t)
tree t;
{
tree cond;
genrtl_do_pushlevel ();
cond = expand_cond (SWITCH_COND (t));
if (cond == error_mark_node)
cond = boolean_false_node;
emit_line_note (input_filename, lineno);
expand_start_case (1, cond, TREE_TYPE (cond), "switch statement", t);
expand_stmt (SWITCH_BODY (t));
expand_end_case_type (cond, SWITCH_TYPE (t), t);
}
tree
build_case_label (low_value, high_value, label_decl)
tree low_value;
tree high_value;
tree label_decl;
{
return build_stmt (CASE_LABEL, low_value, high_value, label_decl);
}
void
genrtl_case_label (case_label)
tree case_label;
{
tree duplicate;
tree cleanup;
cleanup = last_cleanup_this_contour ();
if (cleanup)
{
static int explained = 0;
warning ("destructor needed for `%#D'", (TREE_PURPOSE (cleanup)));
warning ("where case label appears here");
if (!explained)
{
warning ("(enclose actions of previous case statements requiring destructors in their own scope.)");
explained = 1;
}
}
emit_rtx_feedback_counter (CASE_LABEL_DECL (case_label), 0, fdo_outgoing);
add_case_node (CASE_LOW (case_label), CASE_HIGH (case_label),
CASE_LABEL_DECL (case_label), &duplicate);
}
void
genrtl_compound_stmt (t)
tree t;
{
#ifdef ENABLE_CHECKING
struct nesting *n = current_nesting_level ();
#endif
expand_stmt (COMPOUND_BODY (t));
#ifdef ENABLE_CHECKING
if (!COMPOUND_STMT_NO_SCOPE (t) && n != current_nesting_level ())
abort ();
#endif
}
void
genrtl_asm_stmt (cv_qualifier, string, output_operands,
input_operands, clobbers, asm_input_p)
tree cv_qualifier;
tree string;
tree output_operands;
tree input_operands;
tree clobbers;
int asm_input_p;
{
if (cv_qualifier != NULL_TREE
&& cv_qualifier != ridpointers[(int) RID_VOLATILE])
{
warning ("%s qualifier ignored on asm",
IDENTIFIER_POINTER (cv_qualifier));
cv_qualifier = NULL_TREE;
}
emit_line_note (input_filename, lineno);
if (asm_input_p)
expand_asm (string, cv_qualifier != NULL_TREE);
else
c_expand_asm_operands (string, output_operands, input_operands,
clobbers, cv_qualifier != NULL_TREE,
input_filename, lineno);
}
void
genrtl_decl_cleanup (t)
tree t;
{
tree decl = CLEANUP_DECL (t);
if (!decl || (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node))
expand_decl_cleanup_eh (decl, CLEANUP_EXPR (t), CLEANUP_EH_ONLY (t));
}
void
prep_stmt (t)
tree t;
{
if (!STMT_LINENO_FOR_FN_P (t))
lineno = STMT_LINENO (t);
current_stmt_tree ()->stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t);
}
void
expand_stmt (t)
tree t;
{
while (t && t != error_mark_node)
{
int saved_stmts_are_full_exprs_p;
saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
prep_stmt (t);
switch (TREE_CODE (t))
{
case FILE_STMT:
input_filename = FILE_STMT_FILENAME (t);
break;
case RETURN_STMT:
genrtl_return_stmt (t);
break;
case EXPR_STMT:
genrtl_expr_stmt_value (EXPR_STMT_EXPR (t), TREE_ADDRESSABLE (t),
TREE_CHAIN (t) == NULL
|| (TREE_CODE (TREE_CHAIN (t)) == SCOPE_STMT
&& TREE_CHAIN (TREE_CHAIN (t)) == NULL));
break;
case DECL_STMT:
genrtl_decl_stmt (t);
break;
case FOR_STMT:
genrtl_for_stmt (t);
break;
case WHILE_STMT:
genrtl_while_stmt (t);
break;
case DO_STMT:
genrtl_do_stmt (t);
break;
case IF_STMT:
genrtl_if_stmt (t);
break;
case COMPOUND_STMT:
genrtl_compound_stmt (t);
break;
case BREAK_STMT:
genrtl_break_stmt (t);
break;
case CONTINUE_STMT:
genrtl_continue_stmt (t);
break;
case SWITCH_STMT:
genrtl_switch_stmt (t);
break;
case CASE_LABEL:
genrtl_case_label (t);
break;
case LABEL_STMT:
emit_rtx_feedback_counter (LABEL_STMT_LABEL (t), 0, fdo_outgoing);
expand_label (LABEL_STMT_LABEL (t));
break;
case GOTO_STMT:
if (!GOTO_FAKE_P (t)
&& TREE_CODE (GOTO_DESTINATION (t)) == LABEL_DECL
&& flag_guess_branch_prob)
{
rtx note = emit_note (NULL, NOTE_INSN_PREDICTION);
NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_GOTO, NOT_TAKEN);
}
emit_rtx_feedback_counter (t, 0, fdo_outgoing);
genrtl_goto_stmt (GOTO_DESTINATION (t));
break;
case ASM_STMT:
genrtl_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t),
ASM_OUTPUTS (t), ASM_INPUTS (t),
ASM_CLOBBERS (t), ASM_INPUT_P (t));
break;
case SCOPE_STMT:
genrtl_scope_stmt (t);
break;
case CLEANUP_STMT:
genrtl_decl_cleanup (t);
break;
default:
if (lang_expand_stmt)
(*lang_expand_stmt) (t);
else
abort ();
break;
}
current_stmt_tree ()->stmts_are_full_exprs_p
= saved_stmts_are_full_exprs_p;
t = TREE_CHAIN (t);
}
}