#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "cp-tree.h"
#include "c-common.h"
#include "toplev.h"
#include "tree-gimple.h"
#include "hashtab.h"
#include "pointer-set.h"
static void
genericize_try_block (tree *stmt_p)
{
tree body = TRY_STMTS (*stmt_p);
tree cleanup = TRY_HANDLERS (*stmt_p);
gimplify_stmt (&body);
if (CLEANUP_P (*stmt_p))
;
else
gimplify_stmt (&cleanup);
*stmt_p = build2 (TRY_CATCH_EXPR, void_type_node, body, cleanup);
}
static void
genericize_catch_block (tree *stmt_p)
{
tree type = HANDLER_TYPE (*stmt_p);
tree body = HANDLER_BODY (*stmt_p);
gimplify_stmt (&body);
*stmt_p = build2 (CATCH_EXPR, void_type_node, type, body);
}
static void
genericize_eh_spec_block (tree *stmt_p)
{
tree body = EH_SPEC_STMTS (*stmt_p);
tree allowed = EH_SPEC_RAISES (*stmt_p);
tree failure = build_call (call_unexpected_node,
tree_cons (NULL_TREE, build_exc_ptr (),
NULL_TREE));
gimplify_stmt (&body);
*stmt_p = gimple_build_eh_filter (body, allowed, failure);
}
static void
gimplify_if_stmt (tree *stmt_p)
{
tree stmt, cond, then_, else_;
stmt = *stmt_p;
cond = IF_COND (stmt);
then_ = THEN_CLAUSE (stmt);
else_ = ELSE_CLAUSE (stmt);
if (!then_)
then_ = build_empty_stmt ();
if (!else_)
else_ = build_empty_stmt ();
if (integer_nonzerop (cond) && !TREE_SIDE_EFFECTS (else_))
stmt = then_;
else if (integer_zerop (cond) && !TREE_SIDE_EFFECTS (then_))
stmt = else_;
else
stmt = build3 (COND_EXPR, void_type_node, cond, then_, else_);
*stmt_p = stmt;
}
static void
cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p)
{
tree from = TREE_OPERAND (*expr_p, 1);
tree to = TREE_OPERAND (*expr_p, 0);
tree sub;
if (TREE_CODE (from) == TARGET_EXPR)
from = TARGET_EXPR_INITIAL (from);
if (TREE_CODE (from) == CLEANUP_POINT_EXPR)
from = TREE_OPERAND (from, 0);
sub = expr_last (from);
if (TREE_CODE (sub) == AGGR_INIT_EXPR)
{
gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
TREE_OPERAND (sub, 2) = to;
*expr_p = from;
if (from != sub)
TREE_TYPE (from) = void_type_node;
}
}
static void
gimplify_must_not_throw_expr (tree *expr_p, tree *pre_p)
{
tree stmt = *expr_p;
tree temp = voidify_wrapper_expr (stmt, NULL);
tree body = TREE_OPERAND (stmt, 0);
gimplify_stmt (&body);
stmt = gimple_build_eh_filter (body, NULL_TREE,
build_call (terminate_node, NULL_TREE));
if (temp)
{
append_to_statement_list (stmt, pre_p);
*expr_p = temp;
}
else
*expr_p = stmt;
}
int
cp_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p)
{
int saved_stmts_are_full_exprs_p = 0;
enum tree_code code = TREE_CODE (*expr_p);
enum gimplify_status ret;
if (STATEMENT_CODE_P (code))
{
saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
current_stmt_tree ()->stmts_are_full_exprs_p
= STMT_IS_FULL_EXPR_P (*expr_p);
}
switch (code)
{
case PTRMEM_CST:
*expr_p = cplus_expand_constant (*expr_p);
ret = GS_OK;
break;
case AGGR_INIT_EXPR:
simplify_aggr_init_expr (expr_p);
ret = GS_OK;
break;
case THROW_EXPR:
*expr_p = TREE_OPERAND (*expr_p, 0);
ret = GS_OK;
break;
case MUST_NOT_THROW_EXPR:
gimplify_must_not_throw_expr (expr_p, pre_p);
ret = GS_OK;
break;
case INIT_EXPR:
case MODIFY_EXPR:
cp_gimplify_init_expr (expr_p, pre_p, post_p);
ret = GS_OK;
break;
case EMPTY_CLASS_EXPR:
*expr_p = build_int_cst (TREE_TYPE (*expr_p), 0);
ret = GS_OK;
break;
case BASELINK:
*expr_p = BASELINK_FUNCTIONS (*expr_p);
ret = GS_OK;
break;
case TRY_BLOCK:
genericize_try_block (expr_p);
ret = GS_OK;
break;
case HANDLER:
genericize_catch_block (expr_p);
ret = GS_OK;
break;
case EH_SPEC_BLOCK:
genericize_eh_spec_block (expr_p);
ret = GS_OK;
break;
case USING_STMT:
*expr_p = build_empty_stmt ();
ret = GS_ALL_DONE;
break;
case IF_STMT:
gimplify_if_stmt (expr_p);
ret = GS_OK;
break;
default:
ret = c_gimplify_expr (expr_p, pre_p, post_p);
break;
}
if (STATEMENT_CODE_P (code))
current_stmt_tree ()->stmts_are_full_exprs_p
= saved_stmts_are_full_exprs_p;
return ret;
}
static inline bool
is_invisiref_parm (tree t)
{
return ((TREE_CODE (t) == PARM_DECL || TREE_CODE (t) == RESULT_DECL)
&& DECL_BY_REFERENCE (t));
}
static tree
cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
{
tree stmt = *stmt_p;
struct pointer_set_t *p_set = (struct pointer_set_t*) data;
if (is_invisiref_parm (stmt))
{
*stmt_p = convert_from_reference (stmt);
*walk_subtrees = 0;
return NULL;
}
if (pointer_set_contains (p_set, stmt))
{
*walk_subtrees = 0;
return NULL_TREE;
}
if (TREE_CODE (stmt) == ADDR_EXPR
&& is_invisiref_parm (TREE_OPERAND (stmt, 0)))
{
*stmt_p = convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
*walk_subtrees = 0;
}
else if (TREE_CODE (stmt) == RETURN_EXPR
&& TREE_OPERAND (stmt, 0)
&& is_invisiref_parm (TREE_OPERAND (stmt, 0)))
*walk_subtrees = 0;
else if (IS_TYPE_OR_DECL_P (stmt))
*walk_subtrees = 0;
else if (TREE_CODE (stmt) == CLEANUP_STMT)
*stmt_p = build2 (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR
: TRY_FINALLY_EXPR,
void_type_node,
CLEANUP_BODY (stmt),
CLEANUP_EXPR (stmt));
pointer_set_insert (p_set, *stmt_p);
return NULL;
}
void
cp_genericize (tree fndecl)
{
tree t;
struct pointer_set_t *p_set;
for (t = DECL_ARGUMENTS (fndecl); t; t = TREE_CHAIN (t))
if (TREE_ADDRESSABLE (TREE_TYPE (t)))
{
gcc_assert (!DECL_BY_REFERENCE (t));
gcc_assert (DECL_ARG_TYPE (t) != TREE_TYPE (t));
TREE_TYPE (t) = DECL_ARG_TYPE (t);
DECL_BY_REFERENCE (t) = 1;
TREE_ADDRESSABLE (t) = 0;
relayout_decl (t);
}
if (TREE_ADDRESSABLE (TREE_TYPE (DECL_RESULT (fndecl))))
{
t = DECL_RESULT (fndecl);
TREE_TYPE (t) = build_reference_type (TREE_TYPE (t));
DECL_BY_REFERENCE (t) = 1;
TREE_ADDRESSABLE (t) = 0;
relayout_decl (t);
}
if (DECL_CLONED_FUNCTION_P (fndecl))
return;
p_set = pointer_set_create ();
walk_tree (&DECL_SAVED_TREE (fndecl), cp_genericize_r, p_set, NULL);
pointer_set_destroy (p_set);
c_genericize (fndecl);
}