#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "langhooks.h"
#include "ggc.h"
#include "target.h"
#include "cgraph.h"
#include "ipa-prop.h"
#include "tree-flow.h"
#include "tree-pass.h"
#include "flags.h"
#include "timevar.h"
static inline ipa_methodlist_p
ipa_create_methodlist_node (void)
{
return (ipa_methodlist_p) xcalloc (1, sizeof (struct ipa_methodlist));
}
bool
ipa_methodlist_not_empty (ipa_methodlist_p wl)
{
return (wl != NULL);
}
static inline struct cgraph_node *
ipa_methodlist_method (ipa_methodlist_p wl)
{
return wl->method_p;
}
static inline void
ipa_methodlist_method_set (ipa_methodlist_p wl, struct cgraph_node *mt)
{
wl->method_p = mt;
}
static inline ipa_methodlist_p
ipa_methodlist_next_method (ipa_methodlist_p wl)
{
return wl->next_method;
}
static inline void
ipa_methodlist_next_method_set (ipa_methodlist_p wl1, ipa_methodlist_p wl2)
{
wl1->next_method = wl2;
}
ipa_methodlist_p
ipa_methodlist_init (void)
{
struct cgraph_node *node;
ipa_methodlist_p wl;
wl = NULL;
for (node = cgraph_nodes; node; node = node->next)
ipa_add_method (&wl, node);
return wl;
}
void
ipa_add_method (ipa_methodlist_p * wl, struct cgraph_node *mt)
{
ipa_methodlist_p temp;
temp = ipa_create_methodlist_node ();
ipa_methodlist_method_set (temp, mt);
ipa_methodlist_next_method_set (temp, *wl);
*wl = temp;
}
struct cgraph_node *
ipa_remove_method (ipa_methodlist_p * wl)
{
ipa_methodlist_p first;
struct cgraph_node *return_method;
first = *wl;
*wl = ipa_methodlist_next_method (*wl);
return_method = ipa_methodlist_method (first);
free (first);
return return_method;
}
int
ipa_method_formal_count (struct cgraph_node *mt)
{
return IPA_NODE_REF (mt)->ipa_arg_num;
}
void
ipa_method_formal_count_set (struct cgraph_node *mt, int i)
{
IPA_NODE_REF (mt)->ipa_arg_num = i;
}
static inline bool
ipa_method_is_modified (struct cgraph_node *mt, int i)
{
return IPA_NODE_REF (mt)->ipa_mod[i];
}
tree
ipa_method_get_tree (struct cgraph_node *mt, int i)
{
return IPA_NODE_REF (mt)->ipa_param_tree[i];
}
static inline void
ipa_method_tree_map_create (struct cgraph_node *mt)
{
IPA_NODE_REF (mt)->ipa_param_tree =
XCNEWVEC (tree, ipa_method_formal_count (mt));
}
static inline void
ipa_method_modify_create (struct cgraph_node *mt)
{
((struct ipa_node *) mt->aux)->ipa_mod =
XCNEWVEC (bool, ipa_method_formal_count (mt));
}
static inline void
ipa_method_modify_set (struct cgraph_node *mt, int i, bool val)
{
IPA_NODE_REF (mt)->ipa_mod[i] = val;
}
static int
ipa_method_tree_map (struct cgraph_node *mt, tree ptree)
{
int i, count;
count = ipa_method_formal_count (mt);
for (i = 0; i < count; i++)
if (IPA_NODE_REF (mt)->ipa_param_tree[i] == ptree)
return i;
return -1;
}
void
ipa_method_compute_tree_map (struct cgraph_node *mt)
{
tree fndecl;
tree fnargs;
tree parm;
int param_num;
ipa_method_tree_map_create (mt);
fndecl = mt->decl;
fnargs = DECL_ARGUMENTS (fndecl);
param_num = 0;
for (parm = fnargs; parm; parm = TREE_CHAIN (parm))
{
IPA_NODE_REF (mt)->ipa_param_tree[param_num] = parm;
param_num++;
}
}
void
ipa_method_formal_compute_count (struct cgraph_node *mt)
{
tree fndecl;
tree fnargs;
tree parm;
int param_num;
fndecl = mt->decl;
fnargs = DECL_ARGUMENTS (fndecl);
param_num = 0;
for (parm = fnargs; parm; parm = TREE_CHAIN (parm))
param_num++;
ipa_method_formal_count_set (mt, param_num);
}
static void
ipa_method_modify_stmt (struct cgraph_node *mt, tree stmt)
{
int i, j;
switch (TREE_CODE (stmt))
{
case MODIFY_EXPR:
if (TREE_CODE (TREE_OPERAND (stmt, 0)) == PARM_DECL)
{
i = ipa_method_tree_map (mt, TREE_OPERAND (stmt, 0));
if (i >= 0)
ipa_method_modify_set (mt, i, true);
}
break;
case ASM_EXPR:
for (j = 0; j < ipa_method_formal_count (mt); j++)
ipa_method_modify_set (mt, j, true);
break;
default:
break;
}
}
static void
ipa_method_modify_init (struct cgraph_node *mt)
{
int i, count;
ipa_method_modify_create (mt);
count = ipa_method_formal_count (mt);
for (i = 0; i < count; i++)
ipa_method_modify_set (mt, i, false);
}
void
ipa_method_compute_modify (struct cgraph_node *mt)
{
tree decl;
tree body;
int j, count;
basic_block bb;
struct function *func;
block_stmt_iterator bsi;
tree stmt, parm_tree;
ipa_method_modify_init (mt);
decl = mt->decl;
count = ipa_method_formal_count (mt);
if (DECL_UNINLINABLE (decl))
{
for (j = 0; j < count; j++)
ipa_method_modify_set (mt, j, true);
return;
}
for (j = 0; j < count; j++)
{
parm_tree = ipa_method_get_tree (mt, j);
if (TREE_ADDRESSABLE (parm_tree))
ipa_method_modify_set (mt, j, true);
}
body = DECL_SAVED_TREE (decl);
if (body != NULL)
{
func = DECL_STRUCT_FUNCTION (decl);
FOR_EACH_BB_FN (bb, func)
{
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
stmt = bsi_stmt (bsi);
ipa_method_modify_stmt (mt, stmt);
}
}
}
}
int
ipa_callsite_param_count (struct cgraph_edge *cs)
{
return IPA_EDGE_REF (cs)->ipa_param_num;
}
void
ipa_callsite_param_count_set (struct cgraph_edge *cs, int i)
{
IPA_EDGE_REF (cs)->ipa_param_num = i;
}
struct ipa_jump_func *
ipa_callsite_param (struct cgraph_edge *cs, int i)
{
return &(IPA_EDGE_REF (cs)->ipa_param_map[i]);
}
struct cgraph_node *
ipa_callsite_callee (struct cgraph_edge *cs)
{
return cs->callee;
}
static inline void
ipa_callsite_param_set_type (struct cgraph_edge *cs, int i,
enum jump_func_type type1)
{
IPA_EDGE_REF (cs)->ipa_param_map[i].type = type1;
}
static inline void
ipa_callsite_param_set_info_type_formal (struct cgraph_edge *cs, int i,
unsigned int formal)
{
ipa_callsite_param (cs, i)->info_type.formal_id = formal;
}
static inline void
ipa_callsite_param_set_info_type (struct cgraph_edge *cs, int i, tree info_type1)
{
ipa_callsite_param (cs, i)->info_type.value = info_type1;
}
static inline void
ipa_callsite_param_map_create (struct cgraph_edge *cs)
{
IPA_EDGE_REF (cs)->ipa_param_map =
XCNEWVEC (struct ipa_jump_func, ipa_callsite_param_count (cs));
}
static inline tree
ipa_callsite_tree (struct cgraph_edge *cs)
{
return cs->call_stmt;
}
static inline struct cgraph_node *
ipa_callsite_caller (struct cgraph_edge *cs)
{
return cs->caller;
}
void
ipa_callsite_compute_count (struct cgraph_edge *cs)
{
tree call_tree;
tree arg;
int arg_num;
call_tree = get_call_expr_in (ipa_callsite_tree (cs));
gcc_assert (TREE_CODE (call_tree) == CALL_EXPR);
arg = TREE_OPERAND (call_tree, 1);
arg_num = 0;
for (; arg != NULL_TREE; arg = TREE_CHAIN (arg))
arg_num++;
ipa_callsite_param_count_set (cs, arg_num);
}
void
ipa_callsite_compute_param (struct cgraph_edge *cs)
{
tree call_tree;
tree arg, cst_decl;
int arg_num;
int i;
struct cgraph_node *mt;
if (ipa_callsite_param_count (cs) == 0)
return;
ipa_callsite_param_map_create (cs);
call_tree = get_call_expr_in (ipa_callsite_tree (cs));
gcc_assert (TREE_CODE (call_tree) == CALL_EXPR);
arg = TREE_OPERAND (call_tree, 1);
arg_num = 0;
for (; arg != NULL_TREE; arg = TREE_CHAIN (arg))
{
if (TREE_CODE (TREE_VALUE (arg)) == PARM_DECL)
{
mt = ipa_callsite_caller (cs);
i = ipa_method_tree_map (mt, TREE_VALUE (arg));
if (i < 0 || ipa_method_is_modified (mt, i))
ipa_callsite_param_set_type (cs, arg_num, UNKNOWN_IPATYPE);
else
{
ipa_callsite_param_set_type (cs, arg_num, FORMAL_IPATYPE);
ipa_callsite_param_set_info_type_formal (cs, arg_num, i);
}
}
else if (TREE_CODE (TREE_VALUE (arg)) == INTEGER_CST
|| TREE_CODE (TREE_VALUE (arg)) == REAL_CST)
{
ipa_callsite_param_set_type (cs, arg_num, CONST_IPATYPE);
ipa_callsite_param_set_info_type (cs, arg_num,
TREE_VALUE (arg));
}
else if (TREE_CODE (TREE_VALUE (arg)) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (TREE_VALUE (arg), 0)) ==
CONST_DECL)
{
cst_decl = TREE_OPERAND (TREE_VALUE (arg), 0);
if (TREE_CODE (DECL_INITIAL (cst_decl)) == INTEGER_CST
|| TREE_CODE (DECL_INITIAL (cst_decl)) == REAL_CST)
{
ipa_callsite_param_set_type (cs, arg_num,
CONST_IPATYPE_REF);
ipa_callsite_param_set_info_type (cs, arg_num,
DECL_INITIAL (cst_decl));
}
}
else
ipa_callsite_param_set_type (cs, arg_num, UNKNOWN_IPATYPE);
arg_num++;
}
}
enum jump_func_type
get_type (struct ipa_jump_func *jf)
{
return jf->type;
}
union parameter_info *
ipa_jf_get_info_type (struct ipa_jump_func *jf)
{
return &(jf->info_type);
}
void
ipa_node_create (struct cgraph_node *node)
{
node->aux = xcalloc (1, sizeof (struct ipa_node));
}
void
ipa_nodes_create (void)
{
struct cgraph_node *node;
for (node = cgraph_nodes; node; node = node->next)
ipa_node_create (node);
}
void
ipa_edges_create (void)
{
struct cgraph_node *node;
struct cgraph_edge *cs;
for (node = cgraph_nodes; node; node = node->next)
for (cs = node->callees; cs; cs = cs->next_callee)
cs->aux = xcalloc (1, sizeof (struct ipa_edge));
}
void
ipa_nodes_free (void)
{
struct cgraph_node *node;
for (node = cgraph_nodes; node; node = node->next)
{
free (node->aux);
node->aux = NULL;
}
}
void
ipa_edges_free (void)
{
struct cgraph_node *node;
struct cgraph_edge *cs;
for (node = cgraph_nodes; node; node = node->next)
for (cs = node->callees; cs; cs = cs->next_callee)
{
free (cs->aux);
cs->aux = NULL;
}
}
void
ipa_free (void)
{
struct cgraph_node *node;
struct cgraph_edge *cs;
for (node = cgraph_nodes; node; node = node->next)
{
if (node->aux == NULL)
continue;
if (IPA_NODE_REF (node)->ipcp_cval)
free (IPA_NODE_REF (node)->ipcp_cval);
if (IPA_NODE_REF (node)->ipa_param_tree)
free (IPA_NODE_REF (node)->ipa_param_tree);
if (IPA_NODE_REF (node)->ipa_mod)
free (IPA_NODE_REF (node)->ipa_mod);
for (cs = node->callees; cs; cs = cs->next_callee)
{
if (cs->aux)
if (IPA_EDGE_REF (cs)->ipa_param_map)
free (IPA_EDGE_REF (cs)->ipa_param_map);
}
}
}
void
ipa_method_tree_print (FILE * f)
{
int i, count;
tree temp;
struct cgraph_node *node;
fprintf (f, "\nPARAM TREE MAP PRINT\n");
for (node = cgraph_nodes; node; node = node->next)
{
fprintf (f, "method %s Trees :: \n", cgraph_node_name (node));
count = ipa_method_formal_count (node);
for (i = 0; i < count; i++)
{
temp = ipa_method_get_tree (node, i);
if (TREE_CODE (temp) == PARM_DECL)
fprintf (f, " param [%d] : %s\n", i,
(*lang_hooks.decl_printable_name) (temp, 2));
}
}
}
void
ipa_method_modify_print (FILE * f)
{
int i, count;
bool temp;
struct cgraph_node *node;
fprintf (f, "\nMODIFY PRINT\n");
for (node = cgraph_nodes; node; node = node->next)
{
fprintf (f, "method %s :: \n", cgraph_node_name (node));
count = ipa_method_formal_count (node);
for (i = 0; i < count; i++)
{
temp = ipa_method_is_modified (node, i);
if (temp)
fprintf (f, " param [%d] true \n", i);
else
fprintf (f, " param [%d] false \n", i);
}
}
}