another similar bugfix
[libfirm] / ir / opt / funccall.c
index a1b0b76..df717ec 100644 (file)
@@ -2,7 +2,7 @@
  * Project:     libFIRM
  * File name:   ir/opt/ldstopt.c
  * Purpose:     optimization of function calls
- * Author:
+ * Author:      Michael M. Beck
  * Created:
  * CVS-ID:      $Id$
  * Copyright:   (c) 1998-2004 Universität Karlsruhe
@@ -26,6 +26,8 @@
 typedef struct _env_t {
   eset *pure_fkt;   /**< set containing all real functions */
   int  changed;     /**< flag, is set if a graph was changed */
+  int  n_calls_removed_SymConst;
+  int  n_calls_removed_Sel;
 } env_t;
 
 /**
@@ -41,36 +43,68 @@ static void rem_mem_from_real_fkt_calls(ir_node *node, void *env)
   ir_node *call, *ptr, *mem;
   entity *ent;
 
-  if (get_irn_op(node) != op_Proj || get_irn_mode(node) != mode_M)
-    return;
-
-  /* look at Memory Proj's */
-  call = get_Proj_pred(node);
-  if (get_irn_op(call) != op_Call)
-    return;
-
-  ptr = get_Call_ptr(call);
-  if (get_irn_op(ptr) != op_SymConst || get_SymConst_kind(ptr) != symconst_addr_ent)
-    return;
+  if (get_irn_op(node) == op_Call) {
+    call = node;
 
-  ent = get_SymConst_entity(ptr);
+    set_irn_link(call, NULL);
 
-  if (! eset_contains(ctx->pure_fkt, ent))
-    return;
-
-  /* ok, if we get here we found a call to a pure function,
-   * route the NoMem node to the call */
-  mem   = get_Call_mem(call);
-
-  exchange(node, mem);
-  set_Call_mem(call, new_r_NoMem(current_ir_graph));
+    ptr = get_Call_ptr(call);
+    if (get_irn_op(ptr) == op_SymConst && get_SymConst_kind(ptr) == symconst_addr_ent) {
 
-  /* finally, this call can floats */
-  set_irn_pinned(call, op_pin_state_floats);
+      ent = get_SymConst_entity(ptr);
 
-  hook_func_call(current_ir_graph, call);
-
-  ctx->changed = 1;
+      if (! eset_contains(ctx->pure_fkt, ent))
+       return;
+      ctx->n_calls_removed_SymConst++;
+    }
+    else if (get_irn_op(ptr) == op_Sel &&
+            get_irg_callee_info_state(current_ir_graph) == irg_callee_info_consistent) {
+      /* If all possible callees are real functions, we can remove the memory edge. */
+      int i, n_callees = get_Call_n_callees(call);
+      if (n_callees == 0)
+       /* This is kind of strange:  dying code or a Call that will raise an exception
+          when executed as there is no implementation to call.  So better not
+          optimize. */
+       return;
+      for (i = 0; i < n_callees; ++i) {
+       if (! eset_contains(ctx->pure_fkt, get_Call_callee(call, i)))
+         return;
+      }
+      ctx->n_calls_removed_Sel++;
+    }
+    else return;
+
+    /* ok, if we get here we found a call to a pure function,
+     * route the NoMem node to the call */
+    mem   = get_Call_mem(call);
+
+    set_irn_link(call, mem);
+    set_Call_mem(call, new_r_NoMem(current_ir_graph));
+
+    /* finally, this call can float */
+    set_irn_pinned(call, op_pin_state_floats);
+
+    hook_func_call(current_ir_graph, call);
+
+    ctx->changed = 1;
+  } else if (get_irn_op(node) == op_Proj) {
+    call = get_Proj_pred(node);
+    if ((get_irn_op(call) != op_Call) ||
+       (get_irn_op(get_Call_mem(call)) != op_NoMem))
+      return;
+
+    switch(get_Proj_proj(node)) {
+    case pn_Call_M_regular: {
+      ir_node *old_mem = get_irn_link(call);
+      if (old_mem) exchange(node, old_mem);
+    } break;
+    case pn_Call_X_except:
+    case pn_Call_M_except:
+      exchange(node, new_Bad());
+      break;
+    default: ;
+    }
+  }
 }
 
 /*
@@ -86,7 +120,7 @@ void optimize_funccalls(void)
   if (! get_opt_real_func_call())
     return;
 
-  /* first step: detect, which functions are pure, ie do NOT change any memory */
+  /* first step: detect, which functions are pure, i.e. do NOT change any memory */
   for (i = 0, n = get_irp_n_irgs(); i < n; ++i) {
     ir_graph *irg  = get_irp_irg(i);
     ir_node *end   = get_irg_end(irg);
@@ -115,7 +149,7 @@ void optimize_funccalls(void)
         if (change)
           break;
       }
-      else if (op == op_Raise) {
+      else {
         /* exception found */
         change = 1;
         break;
@@ -144,8 +178,11 @@ void optimize_funccalls(void)
 
   if (num_pure > 0) {
     env_t ctx;
+    entity *ent;
 
     ctx.pure_fkt = pure_fkt;
+    ctx.n_calls_removed_SymConst = 0;
+    ctx.n_calls_removed_Sel = 0;
 
     /* all calls of pure functions can be transformed into FuncCalls */
     for (i = 0, n = get_irp_n_irgs(); i < n; ++i) {
@@ -160,6 +197,22 @@ void optimize_funccalls(void)
         set_irg_loopinfo_state(current_ir_graph, loopinfo_cf_inconsistent);
       }
     }
+
+    if (get_firm_verbosity()) {
+      printf("Detected %d functions without side effects.\n", num_pure);
+      printf("Optimizes %d(SymConst) + %d(Sel) calls to these functions.\n",
+            ctx.n_calls_removed_SymConst, ctx.n_calls_removed_Sel);
+      if (get_firm_verbosity() > 1) {
+       for (ent = eset_first(pure_fkt); ent; ent = eset_next(pure_fkt)) {
+         printf("  "); DDMEO(ent);
+       }
+      }
+    }
+
+  } else {
+    if (get_firm_verbosity()) {
+      printf("No functions without side effects detected\n");
+    }
   }
 
   eset_destroy(pure_fkt);