#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "errors.h"
#include "ggc.h"
#include "tree.h"
#include "flags.h"
#include "rtl.h"
#include "tm_p.h"
#include "basic-block.h"
#include "timevar.h"
#include "diagnostic.h"
#include "tree-flow.h"
#include "tree-pass.h"
#include "tree-dump.h"
static void tree_ssa_return (void);
static tree
make_temp (tree type)
{
tree t = create_tmp_var (type, NULL);
add_referenced_tmp_var (t);
bitmap_set_bit (vars_to_rename, var_ann (t)->uid);
return t;
}
static void
tree_ssa_return (void)
{
basic_block bb;
FOR_EACH_BB (bb)
{
tree returnstmt = last_stmt (bb);
edge pred = bb->pred;
basic_block bb_other = NULL;
tree returnstmt_other;
basic_block new_bb = NULL;
tree new_var = NULL;
block_stmt_iterator bsi, bsi_other, new_bsi;
tree ret_decl;
tree type;
if (!pred)
continue;
if (!returnstmt)
continue;
if (TREE_CODE (returnstmt) == RETURN_EXPR)
;
else
continue;
if (!pred || pred->pred_next)
continue;
if (pred->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE))
;
else
continue;
if (pred->flags & EDGE_ABNORMAL)
continue;
if (TREE_OPERAND (returnstmt, 0) == NULL)
continue;
if (pred->src->succ->flags & EDGE_ABNORMAL)
continue;
if (pred->src->succ->dest == bb)
bb_other = pred->src->succ->succ_next->dest;
else
bb_other = pred->src->succ->dest;
if (!bb_other)
continue;
if (bb_other->pred->src != pred->src)
continue;
else if (bb_other->pred->pred_next)
continue;
returnstmt_other = last_stmt (bb_other);
if (!returnstmt_other || TREE_CODE (returnstmt_other) != RETURN_EXPR)
continue;
if (TREE_OPERAND (returnstmt_other, 0) == NULL)
continue;
if (TREE_CODE (TREE_OPERAND (returnstmt, 0)) != MODIFY_EXPR)
continue;
if (TREE_CODE (TREE_OPERAND (returnstmt_other, 0)) != MODIFY_EXPR)
continue;
new_bb = create_empty_bb (bb_other);
redirect_edge_and_branch (bb->succ, new_bb);
redirect_edge_and_branch (bb_other->succ, new_bb);
bsi = bsi_last (bb);
bsi_other = bsi_last (bb_other);
ret_decl = TREE_OPERAND (TREE_OPERAND (returnstmt, 0), 0);
type = TREE_TYPE (ret_decl);
new_var = make_temp (type);
if (TREE_CODE (ret_decl) == SSA_NAME)
ret_decl = SSA_NAME_VAR (ret_decl);
bsi_insert_after (&bsi, build (MODIFY_EXPR, type, new_var,
TREE_OPERAND (TREE_OPERAND (returnstmt, 0), 1)),
BSI_NEW_STMT);
bsi_insert_after (&bsi_other, build (MODIFY_EXPR, type, new_var,
TREE_OPERAND (TREE_OPERAND (returnstmt_other,
0), 1)),
BSI_NEW_STMT);
new_bsi = bsi_last (new_bb);
bsi_insert_after (&new_bsi, build1 (RETURN_EXPR, void_type_node,
build (MODIFY_EXPR, type, ret_decl,
new_var)), TSI_NEW_STMT);
bitmap_set_bit (vars_to_rename, var_ann (ret_decl)->uid);
make_edge (new_bb, EXIT_BLOCK_PTR, 0);
if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
set_immediate_dominator (CDI_DOMINATORS, new_bb, pred->src);
}
cleanup_tree_cfg ();
}
static bool
gate_return (void)
{
return 1;
}
struct tree_opt_pass pass_return =
{
"return",
gate_return,
tree_ssa_return,
NULL,
NULL,
0,
TV_TREE_RETURN,
PROP_cfg | PROP_ssa,
0,
0,
0,
TODO_dump_func | TODO_ggc_collect
| TODO_verify_ssa | TODO_rename_vars
| TODO_verify_flow
};