irgopt: inline_small_irgs implemented
authorGötz Lindenmaier <goetz@ipd.info.uni-karlsruhe.de>
Fri, 22 Feb 2002 15:45:14 +0000 (15:45 +0000)
committerGötz Lindenmaier <goetz@ipd.info.uni-karlsruhe.de>
Fri, 22 Feb 2002 15:45:14 +0000 (15:45 +0000)
[r315]

Changes
ir/ir/irdump.c
ir/ir/irgopt.c
ir/ir/irgopt.h
ir/ir/irnode.c
ir/ir/iropt.c
ir/tr/entity.c
ir/tr/entity.h
ir/tr/type.c
ir/tr/type.h
testprograms/oo_inline_example.c

diff --git a/Changes b/Changes
index 7c68250..7c14de1 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,3 +1,10 @@
+
+  22.2. Goetz
+  irgopt: inline_small_irgs implemented
+
+  30.1. - 20.2. Goetz
+  Bugfixes, some access functions ...
+
   29.1.2002 Goetz
   New directory: ana for analyses.  Adapted configure/makefiles
   implemented irout: backedges.  Added one field to ir_graph, one to ir_node.
index 4173b6e..1c9869d 100644 (file)
@@ -102,7 +102,8 @@ dump_node_opcode (ir_node *n)
   /* SymConst */
   } else if (n->op->code == iro_SymConst) {
     if (get_SymConst_kind(n) == linkage_ptr_info) {
-      xfprintf (F, "SymC %I", get_SymConst_ptrinfo(n));
+      /* don't use get_SymConst_ptr_info as it mangles the name. */
+      xfprintf (F, "SymC %I", n->attr.i.tori.ptrinfo);
     } else {
       assert(get_kind(get_SymConst_type(n)) == k_type);
       assert(get_type_ident(get_SymConst_type(n)));
@@ -157,7 +158,7 @@ dump_node_nodeattr (ir_node *n)
     break;
   case iro_Sel: {
     assert(get_kind(get_Sel_entity(n)) == k_entity);
-    xfprintf (F, "%s", id_to_str(get_entity_ident(get_Sel_entity(n))));
+    xfprintf (F, "%I", get_entity_ident(get_Sel_entity(n)));
     } break;
   default:
   } /* end switch */
@@ -344,7 +345,7 @@ dump_ir_node (ir_node *n)
   case iro_Sel:
     assert(get_kind(get_Sel_entity(n)) == k_entity);
     xfprintf (F, "\"%I ", get_irn_opident(n));
-    xfprintf (F, "%s", id_to_str(get_entity_ident(get_Sel_entity(n))));
+    xfprintf (F, "%I", get_entity_ident(get_Sel_entity(n)));
     xfprintf (F, DEFAULT_NODE_ATTR);
     break;
   case iro_SymConst:
@@ -634,7 +635,7 @@ dump_type_info (type_or_ent *tore, void *env) {
       switch (get_entity_visibility(ent)) {
        case local:              fprintf (F, "local\n");             break;
        case external_visible:   fprintf (F, "external_visible\n");  break;
-       case external_allocated: fprintf (F, "external_allocate\nd");break;
+       case external_allocated: fprintf (F, "external_allocate\n");break;
       }
       switch (get_entity_variability(ent)) {
        case uninitialized: fprintf (F, "uninitialized");break;
@@ -642,6 +643,8 @@ dump_type_info (type_or_ent *tore, void *env) {
        case part_constant: fprintf (F, "part_constant");break;
        case constant:      fprintf (F, "constant");     break;
       }
+      if (is_method_type(get_entity_type(ent)))
+       xfprintf (F, "\n irg = %p ", get_entity_irg(ent));
       xfprintf(F, "\"}\n");
       /* The Edges */
       /* skip this to reduce graph.  Member edge of type is parallel to this edge. *
@@ -1005,8 +1008,9 @@ dump_block_to_cfg (ir_node *block, void *env) {
 
   if (get_irn_opcode(block) == iro_Block) {
     /* This is a block. Dump a node for the block. */
-    xfprintf (F, "node: {title: \"%p\" label: \"%I\"}", block,
-             block->op->name);
+    xfprintf (F, "node: {title:\""); PRINT_NODEID(block);
+    xfprintf (F, "\" label: \"%I ", block->op->name); PRINT_NODEID(block);
+    xfprintf (F, "\"}\n");
     /* Dump the edges */
     for ( i = 0; i < get_Block_n_cfgpreds(block); i++) {
       pred = get_nodes_Block(skip_Proj(get_Block_cfgpred(block, i)));
index 982587e..d9ba118 100644 (file)
@@ -14,6 +14,7 @@
 
 # include <assert.h>
 
+# include "irprog.h"
 # include "irgopt.h"
 # include "irnode_t.h"
 # include "irgraph_t.h"
@@ -22,7 +23,7 @@
 # include "ircons.h"
 # include "misc.h"
 # include "irgmod.h"
-
+# include "array.h"
 # include "pset.h"
 
 /* Defined in iropt.c */
@@ -49,14 +50,20 @@ void init_link (ir_node *n, void *env) {
 
 void
 optimize_in_place_wrapper (ir_node *n, void *env) {
-  int i;
+  int start, i;
   ir_node *optimized;
 
+  if (get_irn_op(n) == op_Block)
+    start = 0;
+  else
+    start = -1;
+
   /* optimize all sons after recursion, i.e., the sons' sons are
      optimized already. */
-  for (i = -1; i < get_irn_arity(n); i++) {
+  for (i = start; i < get_irn_arity(n); i++) {
     optimized = optimize_in_place_2(get_irn_n(n, i));
     set_irn_n(n, i, optimized);
+    assert(get_irn_op(optimized) != op_Id);
   }
 }
 
@@ -66,7 +73,7 @@ local_optimize_graph (ir_graph *irg) {
   current_ir_graph = irg;
 
   /* Handle graph state */
-  // assert(get_irg_phase_state(irg) != phase_building);
+  assert(get_irg_phase_state(irg) != phase_building);
   if (get_opt_global_cse())
     set_irg_pinned(current_ir_graph, floats);
   if (get_irg_outs_state(current_ir_graph) == outs_consistent)
@@ -101,7 +108,6 @@ get_new_node (ir_node * n)
   return n->link;
 }
 
-
 /* We use the block_visited flag to mark that we have computed the
    number of useful predecessors for this block.
    Further we encode the new arity in this flag in the old blocks.
@@ -223,11 +229,13 @@ copy_preds (ir_node *n, void *env) {
     for (i = -1; i < get_irn_arity(n); i++)
       set_irn_n (nn, i, get_new_node(get_irn_n(n, i)));
   }
-  /* Now the new node is complete.  We can add it to the hash table for cse. */
-  add_identities (current_ir_graph->value_table, nn);
+  /* Now the new node is complete.  We can add it to the hash table for cse.
+     @@@ inlinening aborts if we identify End. Why? */
+  if(get_irn_op(nn) != op_End)
+    add_identities (current_ir_graph->value_table, nn);
 }
 
-/* Copies the graph resucsively, compacts the keepalive of the end node. */
+/* Copies the graph recursively, compacts the keepalive of the end node. */
 void
 copy_graph () {
   ir_node *oe, *ne; /* old end, new end */
@@ -346,7 +354,7 @@ dead_node_elimination(ir_graph *irg) {
   current_ir_graph = irg;
 
   /* Handle graph state */
-  // assert(get_irg_phase_state(current_ir_graph) != phase_building);
+  assert(get_irg_phase_state(current_ir_graph) != phase_building);
   free_outs(current_ir_graph);
 
   if (get_optimize() && get_opt_dead_node_elimination()) {
@@ -413,7 +421,7 @@ void inline_method(ir_node *call, ir_graph *called_graph) {
   if (!get_opt_inline()) return;
 
   /* Handle graph state */
-  // assert(get_irg_phase_state(current_ir_graph) != phase_building);
+  assert(get_irg_phase_state(current_ir_graph) != phase_building);
   if (get_irg_outs_state(current_ir_graph) == outs_consistent)
     set_irg_outs_inconsistent(current_ir_graph);
 
@@ -650,3 +658,82 @@ void inline_method(ir_node *call, ir_graph *called_graph) {
     free(cf_pred);
   }
 }
+
+/********************************************************************/
+/* Apply inlineing to small methods.                                */
+/********************************************************************/
+
+static int pos;
+
+/* It makes no sense to inline too many calls in one procedure. Anyways,
+   I didn't get a version with NEW_ARR_F to run. */
+#define MAX_INLINE 1024
+
+static void collect_calls(ir_node *call, void *env) {
+  ir_node **calls = (ir_node **)env;
+  ir_node *addr;
+  tarval *tv;
+  ir_graph *called_irg;
+
+  if (get_irn_op(call) != op_Call) return;
+
+  addr = get_Call_ptr(call);
+  if (get_irn_op(addr) == op_Const) {
+    /* Check whether the constant is the pointer to a compiled entity. */
+    tv = get_Const_tarval(addr);
+    if (tv->u.p.ent) {
+      called_irg = get_entity_irg(tv->u.p.ent);
+      if (called_irg && pos < MAX_INLINE) {
+       /* The Call node calls a locally defined method.  Remember to inline. */
+       calls[pos] = call;
+       pos++;
+      }
+    }
+  }
+}
+
+
+/* Inlines all small methods at call sites where the called address comes
+   from a Const node that references the entity representing the called
+   method.
+   The size argument is a rough measure for the code size of the method:
+   Methods where the obstack containing the firm graph is smaller than
+   size are inlined. */
+void inline_small_irgs(ir_graph *irg, int size) {
+  int i;
+  ir_node *calls[MAX_INLINE];
+  ir_graph *rem = current_ir_graph;
+
+  if (!(get_optimize() && get_opt_inline())) return;
+
+  /*DDME(get_irg_ent(current_ir_graph));*/
+
+  current_ir_graph = irg;
+  /* Handle graph state */
+  assert(get_irg_phase_state(current_ir_graph) != phase_building);
+
+  /* Find Call nodes to inline.
+     (We can not inline during a walk of the graph, as inlineing the same
+     method several times changes the visited flag of the walked graph:
+     after the first inlineing visited of the callee equals visited of
+     the caller.  With the next inlineing both are increased.) */
+  pos = 0;
+  irg_walk(get_irg_end(irg), NULL, collect_calls, (void *) calls);
+
+  if ((pos > 0) && (pos < MAX_INLINE)) {
+    /* There are calls to inline */
+    collect_phiprojs(irg);
+    for (i = 0; i < pos; i++) {
+      tarval *tv;
+      ir_graph *callee;
+      tv = get_Const_tarval(get_Call_ptr(calls[i]));
+      callee = get_entity_irg(tv->u.p.ent);
+      if ((_obstack_memory_used(callee->obst) - obstack_room(callee->obst)) < size) {
+       /*printf(" inlineing "); DDME(tv->u.p.ent);*/
+       inline_method(calls[i], callee);
+      }
+    }
+  }
+
+  current_ir_graph = rem;
+}
index 98bdfa6..89f1d4c 100644 (file)
@@ -19,6 +19,8 @@ void local_optimize_graph (ir_graph *irg);
 /* Performs dead node elimination by copying the ir graph to a new obstack.
    Further removes Bad predecesors from Blocks and the corresponding
    inputs to Phi nodes.
+   Optimization is only performed if options `optimize' and
+   `opt_dead_node_elimination' are set.
    The graph may not be in state phase_building.  The outs datasturcture
    is freed, the outs state set to no_outs. (@@@ Change this? -> inconsistent.)
    Removes old attributes of nodes.  Sets link field to NULL.
@@ -26,6 +28,12 @@ void local_optimize_graph (ir_graph *irg);
    development/debugging are not conserved by copying. */
 void dead_node_elimination(ir_graph *irg);
 
+/* Removes Bad Bad predecesors from Blocks and the corresponding
+   inputs to Phi nodes as in dead_node_elimination but without
+   copying the graph.
+   @@@ not implemented! */
+void remove_bad_predecessors(ir_graph *irg);
+
 /* Inlines a method at the given call site.
    Assumes that call is a Call node in current_ir_graph and that
    the type in the Call nodes type attribute is the same as the
@@ -33,14 +41,14 @@ void dead_node_elimination(ir_graph *irg);
    Further it assumes that all Phi nodes in a block of current_ir_graph
    are assembled in a "link" list in the link field of the corresponding
    block nodes.  Further assumes that all Proj nodes are in a "link" list
-   in the nodes producing the tuple.  (This is only a optical feature
+   in the nodes producing the tuple.  (This is only an optical feature
    for the graph.)  Conserves this feature for the old
    nodes of the graph.  This precondition can be established by a call to
    collect_phisprojs(), see irgmod.h.
    Called_graph must be unequal to current_ir_graph.   Will not inline
    if they are equal.
-   Sets visited masterflag in curren_ir_graph to max of flag in current
-   and called graphs.
+   Sets visited masterflag in current_ir_graph to the max of the flag in
+   current and called graph.
    Removes the call node and splits the basic block the call node
    belongs to.  Inserts a copy of the called graph between these nodes.
    It is recommended to call local_optimize_graph after inlining as this
@@ -48,4 +56,20 @@ void dead_node_elimination(ir_graph *irg);
    combination as control flow operation. */
 void inline_method(ir_node *call, ir_graph *called_graph);
 
+
+/* Inlines all small methods at call sites where the called address comes
+   from a Const node that references the entity representing the called
+   method.
+   The size argument is a rough measure for the code size of the method:
+   Methods where the obstack containing the firm graph is smaller than
+   size are inlined.  Further only a limited number of calls are inlined.
+   If the method contains more than 1024 inlineable calls none will be
+   inlined.
+   Inlining is only performed if flags `optimize' and `inlineing' are set.
+   The graph may not be in state phase_building.
+   It is recommended to call local_optimize_graph after inlining as this
+   function leaves a set of obscure Tuple nodes, e.g. a Proj-Tuple-Jmp
+   combination as control flow operation.  */
+void inline_small_irgs(ir_graph *irg, int size);
+
 # endif /* _IRGOPT_H_ */
index c192d9a..10294ec 100644 (file)
@@ -1830,12 +1830,17 @@ skip_Proj (ir_node *node) {
 
 inline ir_node *
 skip_Tuple (ir_node *node) {
-  if ((node->op == op_Proj) && (get_irn_op(get_Proj_pred(node)) == op_Tuple))
-    return get_Tuple_pred(get_Proj_pred(node), get_Proj_proj(node));
+  ir_node *pred;
+  if (get_irn_op(node) == op_Proj) {
+    pred = skip_nop(get_Proj_pred(node));
+    if (get_irn_op(pred) == op_Proj) /* nested Tuple ? */
+      pred = skip_nop(skip_Tuple(pred));
+    if (get_irn_op(pred) == op_Tuple)
+      return get_Tuple_pred(pred, get_Proj_proj(node));
+  }
   return node;
 }
 
-
 inline ir_node *
 skip_nop (ir_node *node) {
   /* don't assert node !!! */
index 003b6b8..aba0af6 100644 (file)
@@ -419,7 +419,6 @@ equivalent_node (ir_node *n)
       */
       int i, n_preds;
 
-
       ir_node *block = NULL;     /* to shutup gcc */
       ir_node *first_val = NULL; /* to shutup gcc */
       ir_node *scnd_val = NULL;  /* to shutup gcc */
index 4af0836..5322ede 100644 (file)
@@ -84,6 +84,8 @@ new_entity (type *owner, ident *name, type *type)
   res->ld_name = NULL;
   res->overwrites = NEW_ARR_F(entity *, 1);
 
+  res->irg = NULL;
+
   res->visit = 0;
 
   /* Remember entity in it's owner. */
index c7bd82f..eb8e89f 100644 (file)
@@ -109,7 +109,11 @@ typedef struct entity entity;
 #endif
 
 /* Creates a new entity.
-   Automatically inserts the entity as a member of owner. */
+   Automatically inserts the entity as a member of owner.
+   Entity is automatic_allocated and uninitialize except if the type
+   is type_method, then it is static_allocated and constant.  The constant
+   value is a pointer to the method.
+   Visibility is local, offset -1, and it is not volatile. */
 entity     *new_entity (type *owner, ident *name, type *type);
 /* Copies the entity if the new_owner is different from the
    owner of the old entity.  Else returns the old entity.
index f17dece..2a41b24 100644 (file)
@@ -192,7 +192,9 @@ set_type_state(type *tp, type_state state) {
        if (tp != get_glob_type())
          for (i = 0; i < get_class_n_member(tp); i++) {
            assert(get_entity_offset(get_class_member(tp, i)) > -1);
-           /* assert(get_entity_allocation(get_class_member(tp, i)) == automatic_allocated);    @@@ lowerfirm geht nicht durch */
+           assert(is_method_type(get_entity_type(get_class_member(tp, i))) ||
+                  (get_entity_allocation(get_class_member(tp, i)) == automatic_allocated));
+           /*    @@@ lowerfirm geht nicht durch */
          }
       } break;
     case tpo_struct:
@@ -200,7 +202,7 @@ set_type_state(type *tp, type_state state) {
        /* assert(get_type_size(tp) > -1);    @@@ lowerfirm geht nicht durch */
        for (i = 0; i < get_struct_n_member(tp); i++) {
          assert(get_entity_offset(get_struct_member(tp, i)) > -1);
-         /* assert(get_entity_allocation(get_struct_member(tp, i)) == automatic_allocated);    @@@ lowerfirm geht nicht durch */
+         assert((get_entity_allocation(get_struct_member(tp, i)) == automatic_allocated));
        }
       } break;
     case tpo_union:
@@ -406,7 +408,8 @@ inline void free_struct_attrs (type *strct) {
 /* manipulate private fields of struct */
 void    add_struct_member   (type *strct, entity *member) {
   assert(strct && (strct->type_op == type_struct));
-  /*assert(get_type_tpop(get_entity_type(member)) != type_method);          @@@ lowerfirm geht nicht durch */
+  assert(get_type_tpop(get_entity_type(member)) != type_method);
+    /*    @@@ lowerfirm geht nicht durch */
   ARR_APP1 (entity *, strct->attr.sa.members, member);
 }
 int     get_struct_n_member (type *strct) {
@@ -421,7 +424,7 @@ entity *get_struct_member   (type *strct, int pos) {
 void    set_struct_member   (type *strct, int pos, entity *member) {
   assert(strct && (strct->type_op == type_struct));
   assert(pos >= 0 && pos < get_struct_n_member(strct));
-  /* assert(get_entity_type(member)->type_op != type_method); @@@ lowerfirm !!*/
+  assert(get_entity_type(member)->type_op != type_method);/* @@@ lowerfirm !!*/
   strct->attr.sa.members[pos+1] = member;
 }
 void    remove_struct_member(type *strct, entity *member) {
@@ -643,6 +646,15 @@ void  set_array_bounds (type *array, int dimension, ir_node * lower_bound,
   array->attr.aa.lower_bound[dimension] = lower_bound;
   array->attr.aa.upper_bound[dimension] = upper_bound;
 }
+void  set_array_lower_bound_int (type *array, int dimension, int lower_bound) {
+  ir_graph *rem;
+  assert(array && (array->type_op == type_array));
+  rem = current_ir_graph;
+  current_ir_graph = get_const_code_irg();
+  array->attr.aa.lower_bound[dimension] =
+    new_Const(mode_I, tarval_from_long (mode_I, lower_bound));
+  current_ir_graph = rem;
+}
 void  set_array_lower_bound  (type *array, int dimension, ir_node * lower_bound) {
   assert(array && (array->type_op == type_array));
   array->attr.aa.lower_bound[dimension] = lower_bound;
@@ -794,6 +806,7 @@ bool  is_pointer_type            (type *pointer) {
 /* create a new type primitive */
 type *new_type_primitive (ident *name, ir_mode *mode) {
   type *res;
+  /* @@@ assert( mode_is_data(mode) && (!mode == mode_p)); */
   res = new_type(type_primitive, mode, name);
   res->size = get_mode_size(mode);
   res->state = layout_fixed;
index a8d1428..98517c8 100644 (file)
@@ -421,6 +421,7 @@ void  set_array_bounds_int   (type *array, int dimension, int lower_bound,
 void  set_array_bounds       (type *array, int dimension, ir_node *lower_bound,
                                                           ir_node *upper_bound);
 void  set_array_lower_bound  (type *array, int dimension, ir_node *lower_bound);
+void  set_array_lower_bound_int (type *array, int dimension, int lower_bound);
 void  set_array_upper_bound  (type *array, int dimension, ir_node *upper_bound);
 ir_node * get_array_lower_bound  (type *array, int dimension);
 ir_node * get_array_upper_bound  (type *array, int dimension);
index d6f7d94..29a5318 100644 (file)
@@ -274,7 +274,6 @@ main(void)
 
   /****************************************************************************/
 
-
   collect_phiprojs(main_irg);
   current_ir_graph = main_irg;
   printf("Inlining set_a ...\n");