init_cons ();
/* Builds a construct allowing to access all information to be constructed
later. */
+
init_irprog ();
}
# ifndef _FIRM_H_
# define _FIRM_H_
-
-# include "entity.h"
-# include "ircons.h"
+/* The representations */
# include "irprog.h"
# include "type.h"
+# include "entity.h"
+/* Functionality */
+# include "ircons.h"
+# include "irgopt.h"
+
+/* */
# include "xprintf.h"
+/** Global flags. Set these by autoconf?? **/
+/* If this is defined debuging aids are created, e.g. a field in
+ ir_node uniquely numbering the nodes. */
+/* @@@???? this is also set in irnode.h */
+#define DEBUG_libfirm
+
+
/* initialize firm */
void init_firm (void);
res = new_ir_node (current_ir_graph, NULL, op_Block, mode_R, arity, in);
+ irn_vrfy (res);
return res;
}
}
ir_node *
-new_r_Bad (ir_node *block)
+new_r_Bad ()
{
return current_ir_graph->bad;
}
* A less comfortable interface where all predecessors except the block
an operation belongs to need to be specified. SSA must be constructed
by hand. (new_<Node> constructors and switch_block()). This interface
- is called "block oriented".
+ is called "block oriented". It automatically calles the local optimizations
+ for each new node.
* An even less comfortable interface where the block needs to be specified
explicitly. This is called the "raw" interface. (new_r_<Node>
- constructors).
+ constructors). These nodes are not optimized.
To use the functionality of the comfortable interface correctly the Front
End needs to follow certain protocols. This is explained in the following.
int arity, ir_node **in);
ir_node *new_r_Id (ir_graph *irg, ir_node *block,
ir_node *val, ir_mode *mode);
-ir_node *new_r_Bad (ir_node *block);
+ir_node *new_r_Bad ();
/*************************************************************************/
/* routines to dump information about a single node */
/*******************************************************************/
+
+
+inline void
+dump_node_opcode (ir_node *n)
+{
+ /* Const */
+ if (n->op->code == iro_Const) {
+ xfprintf (F, "%v", n->attr.con);
+ /* SymConst */
+ } else if (n->op->code == iro_SymConst) {
+ if (get_SymConst_kind(n) == linkage_ptr_info) {
+ xfprintf (F, "%I", get_SymConst_ptrinfo(n));
+ } else {
+ assert(get_kind(get_SymConst_type(n)) == k_type_class);
+ assert(get_class_ident((type_class *)get_SymConst_type(n)));
+ xfprintf (F, "%s ", id_to_str(get_class_ident((type_class *)get_SymConst_type(n))));
+ if (get_SymConst_kind == type_tag)
+ xfprintf (F, "tag");
+ else
+ xfprintf (F, "size");
+ }
+ /* all others */
+ } else {
+ xfprintf (F, "%I", n->op->name);
+ }
+}
+
+inline void
+dump_node_mode (ir_node *n)
+{
+ switch (n->op->code) {
+ case iro_Phi:
+ case iro_Const:
+ case iro_Id:
+ case iro_Proj:
+ case iro_Conv:
+ case iro_Tuple:
+ case iro_Add:
+ case iro_Sub:
+ case iro_Mul:
+ case iro_And:
+ case iro_Or:
+ case iro_Eor:
+ case iro_Shl:
+ case iro_Shr:
+ case iro_Abs:
+ case iro_Cmp:
+ xfprintf (F, "%I", n->mode->name);
+ break;
+ default:
+ }
+}
+
+inline void
+dump_node_nodeattr (ir_node *n)
+{
+ switch (n->op->code) {
+ case iro_Proj:
+ if (n->in[1]->op->code == iro_Cmp) {
+ xfprintf (F, "%s", get_pnc_string(n->attr.proj));
+ } else {
+ xfprintf (F, "%ld", n->attr.proj);
+ }
+ break;
+ case iro_Sel:
+ assert(n->attr.s.ent->kind == k_entity);
+ xfprintf (F, "%s", id_to_str(n->attr.s.ent->name));
+ /* xdoesn't work for some reason.
+ fprintf (F, "\"%I %I\" ", n->op->name, n->attr.s.ent); */
+ break;
+ default:
+ } /* end switch */
+}
+
+inline void
+dump_node_vcgattr (ir_node *n)
+{
+ switch (n->op->code) {
+ case iro_Start:
+ case iro_End:
+ xfprintf (F, "color: blue");
+ break;
+ case iro_Block:
+ xfprintf (F, "color: lightyellow");
+ break;
+ case iro_Phi:
+ xfprintf (F, "color: green");
+ break;
+ case iro_Const:
+ case iro_Proj:
+ case iro_Tuple:
+ xfprintf (F, "color: yellow");
+ break;
+ default:
+ xfprintf (F, DEFAULT_NODE_ATTR);
+ }
+}
+
+void
+dump_node (ir_node *n) {
+
+ /* dump this node */
+ xfprintf (F, "node: {title: \"%p\" label: \"", n);
+ dump_node_opcode(n);
+ dump_node_mode (n);
+ xfprintf (F, " ");
+ dump_node_nodeattr(n);
+#ifdef DEBUG_libfirm
+ xfprintf (F, " %ld", get_irn_node_nr(n));
+#endif
+ xfprintf (F, "\" ");
+ dump_node_vcgattr(n);
+ xfprintf (F, "}\n");
+}
+
void
dump_ir_node (ir_node *n)
{
fclose (F); /* close vcg file */
}
-
-
/************************************************************************/
/* routines to dump a graph, blocks as conventional nodes. */
/************************************************************************/
void
dump_whole_node (ir_node *n, void* env) {
- dump_ir_node(n);
+ dump_node(n);
dump_ir_block_edge(n);
dump_ir_data_edges(n);
}
ir_node *block = (ir_node *)env;
if (is_no_Block(n) && get_nodes_Block(n) == block) {
- dump_ir_node(n);
+ dump_node(n);
dump_ir_data_edges(n);
}
}
-
void
dump_ir_block (ir_node *block, void *env) {
ir_graph *irg = (ir_graph *)env;
if (get_irn_opcode(block) == iro_Block) {
/* This is a block. So dump the vcg information to make a block. */
- xfprintf(F, "graph: { title: \"%p\" status:clustered color:lightyellow \n",
- block);
+ xfprintf(F, "graph: { title: \"%p\" label: \"", block);
+#ifdef DEBUG_libfirm
+ xfprintf (F, "%ld", get_irn_node_nr(block));
+#elif
+ xfprintf (F, "%I", block->op->name);
+#endif
+ xfprintf(F, "\" status:clustered color:lightyellow \n");
/* dump the blocks edges */
dump_ir_data_edges(block);
/* set the flags with set_flagname, get the flag with get_flagname */
-void
+inline void
set_opt_cse (int value)
{
opt_cse = value;
}
-int
+inline int
get_opt_cse (void)
{
return opt_cse;
}
-void
+inline void
set_opt_constant_folding (int value)
{
opt_constant_folding=value;
}
-int
+inline int
get_opt_constant_folding (void)
{
return opt_constant_folding;
}
-void set_opt_dead_node_elimination (int value)
+inline void
+set_opt_dead_node_elimination (int value)
{
- opt_dead_node_elimination=value;
+ opt_dead_node_elimination = value;
}
-int get_opt_dead_node_elimination (void)
+inline int
+get_opt_dead_node_elimination (void)
{
return opt_dead_node_elimination;
}
-void
+inline void
set_optimize (int value)
{
optimized = value;
}
-int
+inline int
get_optimize (void)
{
return optimized;
**
** Author: Christian Schaefer
**
-** dead node elemination
+** dead node elimination
** walks one time through the whole graph and copies it into another graph,
** so unreachable nodes will be lost.
*/
void *
set_new_node (ir_node *old, ir_node *new)
{
- old->in[0] = new;
+ old->in[0] = new; /* Hi Chris: Benutze old->link, ich hab mich vergewissert dass
+ das hier ueberschrieben werden kann, das erspaart eine
+ indirektion --> schneller. */
return old;
}
new = n->in[0];
assert(new);
- return n->in[0];
+ return new;
}
case iro_End:
res = new_r_End (current_ir_graph, get_new_node(get_nodes_Block(n)));
current_ir_graph -> end = res;
- current_ir_graph -> end_block = get_new_node(get_nodes_Block(n));
+ current_ir_graph -> end_block = get_nodes_Block(res);
break;
case iro_Jmp:
res = new_r_Jmp (current_ir_graph, get_new_node(get_nodes_Block(n)));
break;
case iro_Return:
{
- ir_node **in ;
+ ir_node **in;
in = get_Return_res_arr(n);
for (i = 0; i < get_Return_n_res(n); i++)
set_Return_res(n, i, get_new_node(get_Return_res(n, i)));
case iro_Sel:
{
ir_node **in = get_Sel_index_arr(n);
+ for (i = 0; i < get_Sel_n_index(n); i++)
+ set_Sel_index(n, i, get_new_node(get_Sel_index(n, i)));
res = new_r_Sel (current_ir_graph, get_new_node(get_nodes_Block(n)),
get_new_node(get_Sel_mem(n)),
get_new_node(get_Sel_ptr(n)), get_Sel_n_index(n),
case iro_Call:
{
ir_node **in = get_Call_param_arr(n);
+ for (i = 0; i < get_Call_arity(n); i++)
+ set_Call_param(n, i, get_new_node(get_Call_param(n, i)));
res = new_r_Call (current_ir_graph, get_new_node(get_nodes_Block(n)),
get_new_node(get_Call_mem(n)),
get_new_node(get_Call_ptr(n)), get_Call_arity(n),
case iro_Phi:
{
ir_node **in = get_Phi_preds_arr(n);
+ for (i = 0; i < get_Phi_n_preds(n); i++)
+ set_Phi_pred(n, i, get_new_node(get_Phi_pred(n, i)));
res = new_r_Phi (current_ir_graph, get_new_node(get_nodes_Block(n)),
get_Phi_n_preds(n), in, get_irn_mode(n));
}
case iro_Sync:
{
ir_node **in = get_Sync_preds_arr(n);
+ for (i = 0; i < get_Sync_n_preds(n); i++)
+ set_Sync_pred(n, i, get_new_node(get_Sync_pred(n, i)));
res = new_r_Sync (current_ir_graph, get_new_node(get_nodes_Block(n)),
get_Sync_n_preds(n), in);
}
case iro_Tuple:
{
ir_node **in = get_Tuple_preds_arr(n);
+ for (i = 0; i < get_Tuple_n_preds(n); i++)
+ set_Tuple_pred(n, i, get_new_node(get_Tuple_pred(n, i)));
res = new_r_Tuple (current_ir_graph, get_new_node(get_nodes_Block(n)),
get_Tuple_n_preds(n), in);
}
get_new_node(get_Id_pred(n)), get_irn_mode(n));
break;
case iro_Bad:
- res = new_r_Bad (get_new_node(get_nodes_Block(n)));
+ res = new_r_Bad ();
break;
}
+ /* @@@ Here we could call optimize()!! */
set_new_node(n, res);
}
current_ir_graph->obst = rebirth_obst;
obstack_init (current_ir_graph->obst);
- /* Walks the graph once, and at the recursive way do the copy thing.
- all reachable nodes will be copied to a new obstack. */
-
/*CS*/
printf("Before starting the DEAD NODE ELIMINATION !\n");
+ /* Copy nodes remembered in irg fields first.
+ The optimization contains tests against these fields, e.g., not
+ to optimize the start block away. Therefore these fields have to
+ be fixed first.
+ Further setting these fields in copy_node would impose additional
+ tests for all nodes of a kind.
+ Predict the visited flag the walker will use! */
+ /* Copy the start Block node */
old_node = irg->start_block;
- new_node = new_r_Block (current_ir_graph, 0, NULL);
- irg->start_block = new_node; ;
+ new_node = new_r_Block (current_ir_graph, 0, NULL); /* new_r_Block calls
+ no optimization --> save */
+ irg->start_block = new_node;
+ set_new_node (old_node, new_node);
+ set_irn_visited (new_node, get_irg_visited(current_ir_graph)+1);
+ /* Copy the Start node */
+ old_node = irg->start;
+ new_node = new_r_Start (current_ir_graph, irg->start_block);
+ irg->start = new_node;
+ set_new_node (old_node, new_node);
+ set_irn_visited (new_node, get_irg_visited(current_ir_graph)+1);
+ /* Copy the Bad node */
+ old_node = irg->bad;
+ new_node = new_ir_node (irg, irg->start_block, op_Bad, mode_T, 0, NULL);
+ irg->bad = new_node;
+ set_new_node (old_node, new_node);
+ set_irn_visited (new_node, get_irg_visited(current_ir_graph)+1);
+ /* Copy the Projs for the Start's results. */
+ old_node = irg->frame;
+ new_node = new_r_Proj (irg, irg->start_block, irg->start, mode_p, pns_frame_base);
+ irg->frame = new_node;
set_new_node (old_node, new_node);
set_irn_visited (new_node, get_irg_visited(current_ir_graph)+1);
- /*CS Start node und alle Proj nodes muessen hier per hand eingetragen
- werden! */
+ old_node = irg->globals;
+ new_node = new_r_Proj (irg, irg->start_block, irg->start, mode_p, pns_globals);
+ irg->globals = new_node;
+ set_new_node (old_node, new_node);
+ set_irn_visited (new_node, get_irg_visited(current_ir_graph)+1);
+
+ old_node = irg->args;
+ new_node = new_r_Proj (irg, irg->start_block, irg->start, mode_T, pns_args);
+ irg->args = new_node;
+ set_new_node (old_node, new_node);
+ set_irn_visited (new_node, get_irg_visited(current_ir_graph)+1);
+
+ /* Walks the graph once, and at the recursive way do the copy thing.
+ all reachable nodes will be copied to a new obstack. */
irg_walk(irg->end, NULL, copy_node, NULL);
+
/*CS*/
printf("After the DEAD NODE ELIMINATION !\n");
xfree (graveyard_obst);
}
- /* Free memory from old unoptimized obstack */
- xfree (graveyard_obst);
-
current_ir_graph = rem;
}
**
** Author: Christian Schaefer
**
-** dead node elemination
+** dead node elimination
** walks one time through the whole graph and copies it into another graph,
** so unreachable nodes will be lost.
*/
void local_optimize_graph (ir_graph *irg);
/* Performs dead node elimination by copying the ir graph to a new obstack. */
-void dead_node_elemination(ir_graph *irg);
+void dead_node_elimination(ir_graph *irg);
# endif /* _IRGOPT_H_ */
memcpy (&res->in[1], in, sizeof (ir_node *) * arity);
}
res->in[0] = block;
+
+#ifdef DEBUG_libfirm
+ res->node_nr = get_irp_new_node_nr();
+#endif
+
return res;
}
return printed;
}
- XPF1 ("%I", get_irn_op(np)->name);
+ XPF1 ("%I", get_irn_opname(np));
switch (get_irn_opcode (np)) { /* node label */
case iro_Const:
return node->mode->code;
}
+
+inline ident *
+get_irn_modename (ir_node *node)
+{
+ assert(node);
+ return node->mode->name;
+}
+
inline ir_op *
get_irn_op (ir_node *node)
{
node->op = op;
}
-inline void
-set_irn_visited (ir_node *node, unsigned long visited)
+inline opcode
+get_irn_opcode (ir_node *node)
{
assert (node);
- node->visited = visited;
+ return node->op->code;
+}
+
+inline ident *
+get_irn_opname (ir_node *node)
+{
+ assert(node);
+ return node->op->name;
}
inline unsigned long
return node->visited;
}
-inline opcode
-get_irn_opcode (ir_node *node)
+inline void
+set_irn_visited (ir_node *node, unsigned long visited)
{
assert (node);
- return node->op->code;
+ node->visited = visited;
}
-
inline void
set_irn_link (ir_node *node, ir_node *link) {
assert (node);
return node->link;
}
+#ifdef DEBUG_libfirm
+/* Outputs a unique number for this node */
+inline long
+get_irn_node_nr(ir_node *node) {
+ assert(node);
+ return node->node_nr;
+}
+#endif
+
inline tarval *
get_irn_const_attr (ir_node *node)
{
# include "tv.h"
# include "type.h"
+
+/** Global flags. Set these by autoconf?? **/
+/* If this is defined debuging aids are created, e.g. a field in
+ ir_node uniquely numbering the nodes. */
+/* @@@???? this is also set in firm.h */
+#define DEBUG_libfirm
+#ifdef DEBUG_libfirm
+#include "irprog.h"
+#endif
+
/* projection numbers of compare. */
enum {
False, /* false */
used while construction to link Phi0 nodes and
during optimization to link to nodes that
shall replace a node. */
+#ifdef DEBUG_libfirm
+ int node_nr; /* a unique node number for each node to make output
+ readable. */
+#endif
attr attr; /* attribute of this node. Depends on opcode. */
/* Must be last field of struct ir_node. */
};
To iterate over the operands iterate from 0 to i < get_irn_arity(),
to iterate includind the Block predecessor iterate from i = -1 to
i < get_irn_arity. */
+/* Access predecessor n */
inline ir_node *get_irn_n (ir_node *node, int n);
inline void set_irn_n (ir_node *node, int n, ir_node *in);
+/* Get the mode struct. */
inline ir_mode *get_irn_mode (ir_node *node);
+/* Get the mode-enum modecode */
inline modecode get_irn_modecode (ir_node *node);
-inline void set_irn_op (ir_node *node, ir_op *op);
+/* Get the ident for a string representation of the mode */
+inline ident *get_irn_modename (ir_node *node);
+/* Access the opcode struct of the node */
inline ir_op *get_irn_op (ir_node *node);
+inline void set_irn_op (ir_node *node, ir_op *op);
+/* Get the opcode-enum of the node */
+inline opcode get_irn_opcode (ir_node *node);
+/* Get the ident for a string representation of the opcode */
+inline ident *get_irn_opname (ir_node *node);
inline void set_irn_visited (ir_node *node, unsigned long visited);
inline unsigned long get_irn_visited (ir_node *node);
-/* should be private to the library: */
-inline opcode get_irn_opcode (ir_node *node);
inline void set_irn_link (ir_node *node, ir_node *link);
inline ir_node *get_irn_link (ir_node *node);
+#ifdef DEBUG_libfirm
+/* Outputs a unique number for this node */
+inline long get_irn_node_nr(ir_node *node);
+#endif
/** access attributes directly **/
inline tarval *get_irn_const_attr (ir_node *node);
inline ir_node **get_Sel_index_arr (ir_node *node);
inline int get_Sel_n_index (ir_node *node);
/*inline void set_Sel_n_index (ir_node *node, int n_index); */
-
-
-inline ir_node *get_Call_mem (ir_node *node);
-inline void set_Call_mem (ir_node *node, ir_node *mem);
-inline ir_node *get_Call_ptr (ir_node *node);
-inline void set_Call_ptr (ir_node *node, ir_node *ptr);
-inline ir_node **get_Call_param_arr (ir_node *node);
-inline int get_Call_arity (ir_node *node);
-
inline ir_node *get_Sel_index (ir_node *node, int pos);
inline void set_Sel_index (ir_node *node, int pos, ir_node *index);
inline entity *get_Sel_entity (ir_node *node); /* entity to select */
inline void set_Call_mem (ir_node *node, ir_node *mem);
inline ir_node *get_Call_ptr (ir_node *node);
inline void set_Call_ptr (ir_node *node, ir_node *ptr);
+inline ir_node **get_Call_param_arr (ir_node *node);
inline int get_Call_arity (ir_node *node);
/* inline void set_Call_arity (ir_node *node, ir_node *arity); */
inline ir_node *get_Call_param (ir_node *node, int pos);
of an exception. */
int is_fragile_op(ir_node *node);
+
+
+/* Makros for debugging the libfirm */
+#ifdef DEBUG_libfirm
+#include "ident.h"
+
+#define DDMSG printf("%s(l.%i)\n", __FUNCTION__, __LINE__)
+#define DDMSG1(X) printf("%s(l.%i) %s\n", __FUNCTION__, __LINE__, \
+ ID_TO_STR(get_irn_opname(X)))
+#define DDMSG2(X) printf("%s(l.%i) %s: %ld\n", __FUNCTION__, __LINE__, \
+ ID_TO_STR(get_irn_opname(X)), get_irn_node_nr(X))
+
+#endif
+
# endif /* _IRNODE_H_ */
assert(irp);
ARR_APP1 (type *, irp->types, typ);
}
+
+int get_irp_new_node_nr() {
+ assert(irp);
+ irp->max_node_nr = irp->max_node_nr + 1;
+ return irp->max_node_nr - 1;
+}
fields and procedures. Does this work?
Better name??? @@@ */
/*struct obstack *obst; * @@@ Should we place all types and entities themselves
- on an obstack, too? */
+ on an obstack, too? */
+#ifdef DEBUG_libfirm
+ long max_node_nr;
+#endif
} ir_prog;
/* A variable from where everything in the ir can be accessed. */
/* Adds type to the list of types in irp. */
void add_irp_type(type *typ);
+
+/* Returns a new, unique number to number nodes or the like. */
+int get_irp_new_node_nr();
+
#endif /* ifndef _IRPROG_H_ */
clean:
rm -f \
- empty.o empty \
- const_eval_example.o const_eval_example \
- if_example.o if_example \
- if_else_example.o if_else_example \
- if_while_example.o if_while_example \
- cond_example.o cond_example \
- call_str_example.o call_str_example \
- memory_example.o memory_example \
- array-stack_example.o array-stack_example \
- array-heap_example.o array-heap_example \
- oo_program_example.o oo_program_example \
- irr_cf_example.o irr_cf_example \
- irr_loop_example.o irr_loop_example \
- dead_block_example.o dead_block_example \
- global_var_example *.vcg core
+ empty const_eval_example \
+ if_example if_else_example \
+ if_while_example cond_example \
+ call_str_example memory_example \
+ array-stack_example array-heap_example \
+ oo_program_example irr_cf_example \
+ irr_loop_example dead_block_example \
+ global_var_example \
+ *.o *.vcg core
realclean: clean
printf("creating an IR graph: CONST_EVAL_EXAMPLE...\n");
+
init_firm ();
+
/* Try both optimizations: */
set_opt_constant_folding(1);
set_opt_cse(1);
+ set_opt_dead_node_elimination (0);
owner = new_type_class (id_from_str ("CONST_EVAL_EXAMPLE", 18));
ent = new_entity ((type *)owner, id_from_str ("main", 4), NULL);
c = new_Proj(c, mode_i, 2);
*/
-
- /*
c = new_Add (new_Const (mode_i, tarval_from_long (mode_i, 5)),
new_Const (mode_i, tarval_from_long (mode_i, 7)),
mode_i);
d = new_Add (new_Const (mode_i, tarval_from_long (mode_i, 7)),
new_Const (mode_i, tarval_from_long (mode_i, 5)),
mode_i);
- */
+
{
ir_node *in[2];
in[0] = c;
/* verify the graph */
irg_vrfy(irg);
+ dead_node_elimination(irg);
+
+ irg_vrfy(irg);
+
printf("\nDone building the graph. Dumping it.\n");
dump_ir_block_graph (irg);