no environment anymore for emitters
[libfirm] / ir / opt / funccall.c
index d2f152a..9c5b156 100644 (file)
@@ -1,13 +1,34 @@
 /*
- * Project:     libFIRM
- * File name:   ir/opt/funccall.c
- * Purpose:     optimization of function calls
- * Author:      Michael Beck
- * Created:
- * CVS-ID:      $Id$
- * Copyright:   (c) 1998-2004 Universit�t Karlsruhe
- * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
+ * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
  */
+
+/**
+ * @file
+ * @brief   Optimization of function calls.
+ * @author  Michael Beck
+ * @version $Id$
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "iroptimize.h"
+
 #include "irnode_t.h"
 #include "irgraph_t.h"
 #include "irgmod.h"
@@ -16,7 +37,6 @@
 #include "dbginfo_t.h"
 #include "irflag_t.h"
 #include "ircons.h"
-#include "funccall.h"
 #include "irhooks.h"
 
 /**
@@ -32,36 +52,37 @@ typedef struct _env_t {
 
 /**
  * Collect all calls to const and pure functions
- * to lists. Collect of Proj nodes into a Proj list.
+ * to lists. Collect all Proj(Call) nodes into a Proj list.
  */
 static void collect_calls(ir_node *node, void *env)
 {
   env_t *ctx = env;
   ir_node *call, *ptr;
-  entity *ent;
+  ir_entity *ent;
   unsigned mode;
 
-  if (get_irn_op(node) == op_Call) {
+  if (is_Call(node)) {
     call = node;
 
+    /* set the link to NULL for all non-const/pure calls */
     set_irn_link(call, NULL);
     ptr = get_Call_ptr(call);
-    if (get_irn_op(ptr) == op_SymConst && get_SymConst_kind(ptr) == symconst_addr_ent) {
+    if (is_SymConst(ptr) && get_SymConst_kind(ptr) == symconst_addr_ent) {
       ent = get_SymConst_entity(ptr);
 
       mode = get_entity_additional_properties(ent);
-      if (mode & (mtp_property_const|mtp_property_pure) == 0)
+      if ((mode & (mtp_property_const|mtp_property_pure)) == 0)
         return;
       ++ctx->n_calls_removed_SymConst;
-    }
-    else if (is_Sel(ptr) &&
-            get_irg_callee_info_state(current_ir_graph) == irg_callee_info_consistent) {
+    } else if (get_opt_closed_world() &&
+              is_Sel(ptr) &&
+              get_irg_callee_info_state(current_ir_graph) == irg_callee_info_consistent) {
       /* If all possible callees are const 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. */
+           when executed as there is no implementation to call.  So better not
+           optimize. */
         return;
 
       /* note that const function are a subset of pure ones */
@@ -77,29 +98,27 @@ static void collect_calls(ir_node *node, void *env)
           return;
       }
       ++ctx->n_calls_removed_Sel;
-    }
-    else
+    } else
       return;
 
     /* ok, if we get here we found a call to a const or a pure function */
     if (mode & mtp_property_pure) {
       set_irn_link(call, ctx->pure_call_list);
       ctx->pure_call_list = call;
-    }
-    else {
+    } else {
       set_irn_link(call, ctx->const_call_list);
       ctx->const_call_list = call;
     }
-  }
-  else if (get_irn_op(node) == op_Proj) {
+  } else if (is_Proj(node)) {
     /*
      * Collect all memory and exception Proj's from
      * calls.
      */
     call = get_Proj_pred(node);
-    if (get_irn_op(call) != op_Call)
+    if (! is_Call(call))
       return;
 
+    /* collect the Proj's in the Proj list */
     switch (get_Proj_proj(node)) {
     case pn_Call_M_regular:
     case pn_Call_X_except:
@@ -111,20 +130,24 @@ static void collect_calls(ir_node *node, void *env)
       break;
     }
   }
-}  /* rem_mem_from_const_fkt_calls */
+}  /* collect_calls */
 
 /**
  * Fix the list of collected Calls.
  *
  * @param irg        the graph that contained calls to pure functions
- * @param call_list  the list of all call sites of pure functions
- * @param proj_list  the list of all memory/exception Projs of this call sites
+ * @param call_list  the list of all call sites of const functions
+ * @param proj_list  the list of all memory/exception Proj's of this call sites
  */
 static void fix_const_call_list(ir_graph *irg, ir_node *call_list, ir_node *proj_list) {
   ir_node *call, *next, *mem, *proj;
   int exc_changed = 0;
+  ir_graph *rem = current_ir_graph;
+
+  current_ir_graph = irg;
 
-  /* fix all calls by removing it's memory input */
+  /* First step: fix all calls by removing it's memory input.
+     It's original memory input is preserved in their link fields. */
   for (call = call_list; call; call = next) {
     next = get_irn_link(call);
     mem  = get_Call_mem(call);
@@ -142,7 +165,7 @@ static void fix_const_call_list(ir_graph *irg, ir_node *call_list, ir_node *proj
      *   function be called even if the loop/if is not entered ...
      *
      * This could be fixed using post-dominators for calls and Pin nodes
-     * but need some more analyses to ensure that a call that potential
+     * but need some more analyzes to ensure that a call that potential
      * never returns is not executed before some code that generates
      * observable states...
      */
@@ -152,17 +175,22 @@ static void fix_const_call_list(ir_graph *irg, ir_node *call_list, ir_node *proj
     hook_func_call(irg, call);
   }
 
-  /* finally fix all Proj's */
+  /* Second step: fix all Proj's */
   for (proj = proj_list; proj; proj = next) {
     next = get_irn_link(proj);
     call = get_Proj_pred(proj);
     mem  = get_irn_link(call);
-    if (! mem)
+
+    /* beware of calls in the pure call list */
+    if (! mem || get_irn_op(mem) == op_Call)
       continue;
+    assert(get_irn_mode(mem) == mode_M);
 
     switch (get_Proj_proj(proj)) {
     case pn_Call_M_regular: {
-      exchange(proj, mem);
+      /* in dead code there might be cycles where proj == mem */
+      if (proj != mem)
+        exchange(proj, mem);
     } break;
     case pn_Call_X_except:
     case pn_Call_M_except:
@@ -176,15 +204,16 @@ static void fix_const_call_list(ir_graph *irg, ir_node *call_list, ir_node *proj
 
   /* changes were done ... */
   set_irg_outs_inconsistent(irg);
-  set_irg_loopinfo_state(current_ir_graph, loopinfo_cf_inconsistent);
+  set_irg_loopinfo_state(irg, loopinfo_cf_inconsistent);
 
   if (exc_changed) {
     /* ... including exception edges */
     set_irg_doms_inconsistent(irg);
   }
+  current_ir_graph = rem;
 }  /* fix_call_list */
 
-
+#if 0
 /**
  * Check if a graph represents a const function.
  *
@@ -253,6 +282,7 @@ static int is_const_function(ir_graph *irg)
   }
   return 0;
 }  /* is_const_function */
+#endif
 
 /* a marker */
 static char _mark;
@@ -316,8 +346,8 @@ static unsigned _follow_mem(ir_node *node) {
       ptr = get_Call_ptr(node);
       if (get_irn_op(ptr) == op_SymConst &&
           get_SymConst_kind(ptr) == symconst_addr_ent) {
-        entity   *ent = get_SymConst_entity(ptr);
-        ir_graph *irg = get_entity_irg(ent);
+        ir_entity *ent = get_SymConst_entity(ptr);
+        ir_graph  *irg = get_entity_irg(ent);
 
         if (irg == current_ir_graph) {
           /* A recursive call. The did not mode depend on this call */
@@ -423,7 +453,7 @@ static int is_pure_function(ir_graph *irg) {
     }
     else {
       /* exception found. */
-      mode = follow_mem(irg, mem, mode);
+      mode = follow_mem(irg, node, mode);
       break;
     }
     if (mode == 0)