Updated header
[libfirm] / ir / ana2 / typalise.c
index 42e3e52..bced3f0 100644 (file)
@@ -1,18 +1,31 @@
 /* -*- c -*- */
 
 /*
- * Project:     libFIRM
- * File name:   ir/ana2/pto.c
- * Purpose:     Pto
- * Author:      Florian
- * Modified by:
- * Created:     Mon 18 Oct 2004
- * CVS-ID:      $Id$
- * Copyright:   (c) 1999-2004 Universität Karlsruhe
- * Licence:     This file is 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     Pto
+ * @author    Florian
+ * @date      Mon 18 Oct 2004
+ * @version   $Id$
+ */
 # ifdef HAVE_CONFIG_H
 #  include "config.h"
 # endif
@@ -34,6 +47,8 @@
 # include "irgwalk.h"
 # include "xmalloc.h"
 # include "gnu_ext.h"
+# include "irdump.h"
+# include "typewalk.h"
 
 
 /*
@@ -47,11 +62,47 @@ static long ta_id = 0;
 */
 static typalise_t *typalise_proj (ir_node*);
 
+/* DEBUGGING only */
+static void cough_and_die (ir_node *node)
+{
+  ir_graph *graph = get_irn_irg (node);
+
+  fprintf (stdout, "%s: %s[%li]\n",
+           __FUNCTION__,
+           get_op_name (get_irn_op (node)),
+           get_irn_node_nr (node));
+  dump_ir_block_graph (graph, "-typealise");
+  assert (0);
+}
+
+/*
+  Exception b/d
+*/
+static ir_type *java_lang_Throwable_tp = NULL;
+
+static ir_type *get_java_lang_Throwable (void)
+{
+  assert (NULL != java_lang_Throwable_tp);
+
+  return (java_lang_Throwable_tp);
+}
+
+static void find_java_lang_Throwable (ir_type *tp, void *_unused)
+{
+  const char *name = get_type_name (tp);
+
+  if (0 == strcmp (name, "java/lang/Throwable")) {
+    assert (NULL == java_lang_Throwable_tp);
+
+    java_lang_Throwable_tp = tp;
+  }
+}
+
 
 /*
   Ctors, Dtors for typalise_t-s
 */
-static typalise_t *ta_exact (type *tp)
+static typalise_t *ta_exact (ir_type *tp)
 {
   typalise_t *ta = xmalloc (sizeof (typalise_t));
   ta->kind = type_exact;
@@ -73,7 +124,7 @@ static typalise_t *ta_types (lset_t *set)
   return (ta);
 }
 
-static typalise_t *ta_type (type *tp)
+static typalise_t *ta_type (ir_type *tp)
 {
   typalise_t *ta = xmalloc (sizeof (typalise_t));
   ta->kind = type_type;
@@ -106,7 +157,7 @@ static void ta_delete (typalise_t *ta)
    Find out whether otype is a subtype of stype.
    Return non-zero iff otype is a subtype of stype.
 */
-static int is_subtype (type *otype, type *stype)
+static int is_subtype (ir_type *otype, ir_type *stype)
 {
   int n_sub = get_class_n_subtypes (stype);
   int is_sub = FALSE;
@@ -117,7 +168,7 @@ static int is_subtype (type *otype, type *stype)
   }
 
   for (i = 0; (!is_sub) && (i < n_sub); i ++) {
-    type *sub = get_class_subtype (stype, i);
+    ir_type *sub = get_class_subtype (stype, i);
 
     is_sub |= is_subtype (otype, sub);
   }
@@ -131,7 +182,7 @@ static int is_subtype (type *otype, type *stype)
     Compute the closure of all subtypes of otype (including otype
     itself)
 */
-static void _collect_subtypes (type *otype, lset_t *set)
+static void _collect_subtypes (ir_type *otype, lset_t *set)
 {
   int i, n_sub;
 
@@ -139,13 +190,13 @@ static void _collect_subtypes (type *otype, lset_t *set)
 
   n_sub = get_class_n_subtypes (otype);
   for (i = 0; i < n_sub; i ++) {
-    type *sub = get_class_subtype (otype, i);
+    ir_type *sub = get_class_subtype (otype, i);
 
     _collect_subtypes (sub, set);
   }
 }
 
-static lset_t *subtype_closure (type *otype)
+static lset_t *subtype_closure (ir_type *otype)
 {
   lset_t *set = lset_create ();
 
@@ -157,7 +208,7 @@ static lset_t *subtype_closure (type *otype)
 /**
    Helper method for get_owner_types
 */
-static void _collect_owner_types (entity *method, ir_graph *graph, lset_t *tps)
+static void _collect_owner_types (ir_entity *method, ir_graph *graph, lset_t *tps)
 {
   int i, n_over;
 
@@ -180,7 +231,7 @@ static void _collect_owner_types (entity *method, ir_graph *graph, lset_t *tps)
 
   n_over = get_entity_n_overwrittenby (method);
   for (i = 0; i < n_over; i ++) {
-    entity *ometh = get_entity_overwrittenby (method, i);
+    ir_entity *ometh = get_entity_overwrittenby (method, i);
 
     _collect_owner_types (ometh, graph, tps);
   }
@@ -193,7 +244,7 @@ static void _collect_owner_types (entity *method, ir_graph *graph, lset_t *tps)
 static lset_t *get_owner_types (ir_graph *graph)
 {
   lset_t *tps = lset_create ();
-  entity *meth = get_irg_entity (graph);
+  ir_entity *meth = get_irg_entity (graph);
 
   _collect_owner_types (meth, graph, tps);
 
@@ -203,9 +254,9 @@ static lset_t *get_owner_types (ir_graph *graph)
 /**
    Return a list containing all types of 'set' which are a subtype of 'type'.
 */
-static lset_t *filter_for_type (lset_t *set, type *stype)
+static lset_t *filter_for_type (lset_t *set, ir_type *stype)
 {
-  type *curs = (type*) lset_first (set);
+  ir_type *curs = (ir_type*) lset_first (set);
   lset_t *lset = lset_create ();
 
   while (NULL != curs) {
@@ -230,6 +281,15 @@ static typalise_t *ta_join (typalise_t *one, typalise_t *two)
 {
   typalise_t *res = NULL;
 
+  /* now, one==NULL or two==NULL cannot happen legitimately (if we hit a NULL pointer constant)
+  if (NULL == one) {
+    return (two);
+  }
+
+  if (NULL == two) {
+    return (one);
+  }
+  */
   switch (one->kind) {
   case (type_invalid): { /* shut up, gcc */ }
   case (type_exact): {
@@ -302,8 +362,8 @@ static typalise_t *ta_join (typalise_t *one, typalise_t *two)
       res = ta_join (two, one);
     } break;
     case (type_type): {
-      type *one_type = one->res.type;
-      type *two_type = two->res.type;
+      ir_type *one_type = one->res.type;
+      ir_type *two_type = two->res.type;
 
       if (is_subtype (one_type, two_type)) {
         ta_delete (one);
@@ -350,7 +410,7 @@ static const char *ta_name (typalise_t *ta)
   case (type_types): {
     len += sprintf (buf+len, "one_of ");
 
-    type *iter = lset_first (ta->res.types);
+    ir_type *iter = lset_first (ta->res.types);
 
     int size = BUF_SIZE - len - 1;
     while ((NULL != iter) && (0 < size)) {
@@ -376,9 +436,9 @@ static const char *ta_name (typalise_t *ta)
    method.  Presumably, this is because clazz inherits the graph as
    the implementation for a method.
 */
-static int uses_graph (type *clazz, entity *meth, ir_graph *graph)
+static int uses_graph (ir_type *clazz, ir_entity *meth, ir_graph *graph)
 {
-  type *g_clazz = get_entity_owner (meth);
+  ir_type *g_clazz = get_entity_owner (meth);
   int i, n_over, use = FALSE;
 
   if (g_clazz == clazz) {
@@ -396,7 +456,7 @@ static int uses_graph (type *clazz, entity *meth, ir_graph *graph)
   /* else inherited or description */
   n_over = get_entity_n_overwrittenby (meth); /* DOWN-wards */
   for (i = 0; (i < n_over) && (!use); i ++) {
-    entity *over = get_entity_overwrittenby (meth, i);
+    ir_entity *over = get_entity_overwrittenby (meth, i);
 
     use |= uses_graph (clazz, over, graph);
   }
@@ -424,8 +484,8 @@ static int ta_supports (typalise_t *ta, ir_graph *graph)
     return (res);
   }
   case (type_type): {
-    entity *meth = get_irg_entity (graph);
-    type *tp = get_entity_owner (meth);
+    ir_entity *meth = get_irg_entity (graph);
+    ir_type *tp = get_entity_owner (meth);
     int res = is_subtype (tp, ta->res.type);
 
     if (res) {
@@ -437,7 +497,7 @@ static int ta_supports (typalise_t *ta, ir_graph *graph)
     return (res);
   }
   case (type_types): {
-    type *tp = get_entity_owner (get_irg_entity (graph));
+    ir_type *tp = get_entity_owner (get_irg_entity (graph));
 
     return (lset_contains (ta->res.types, tp));
   }
@@ -451,8 +511,104 @@ static int ta_supports (typalise_t *ta, ir_graph *graph)
 /* =========== WHAT ELSE ? =========== */
 
 /*
-  Helper to typalise (ir_node*)
+  Helpers to typalise (ir_node*)
+*/
+/**
+   Find an approximation to the given load node's value's types
 */
+static typalise_t *typalise_call (ir_node *call)
+{
+  ir_entity *ent = NULL;
+  ir_type *tp = NULL;
+  typalise_t *res = NULL;
+  ir_node *call_ptr = get_Call_ptr (call);
+
+  if (iro_Sel == get_irn_opcode (call_ptr)) {
+    ent = get_Sel_entity (call_ptr);
+  } else if (iro_SymConst == get_irn_opcode (call_ptr)) {
+    if (get_SymConst_kind (call_ptr) == symconst_addr_ent) {
+      ent = get_SymConst_entity (call_ptr);
+    } else if (get_SymConst_kind (call_ptr) == symconst_addr_name) {
+      ident *id = get_SymConst_name (call_ptr);
+      const char *name = get_id_str (id);
+      if (0 == strcmp (name, "iro_Catch")) {
+        res = ta_type (java_lang_Throwable_tp);
+
+        return (res);
+      }
+
+      fprintf (stdout, "%s: cannot handle Call[%li] (symconst_addr_name=\"%s\")\n",
+               __FUNCTION__, get_irn_node_nr (call),
+               name);
+      cough_and_die (call_ptr);
+    } else if (get_SymConst_kind (call_ptr) == symconst_type_tag) {
+      fprintf (stdout, "%s: cannot handle Call[%li] (symconst_type_tag)\n",
+               __FUNCTION__, get_irn_node_nr (call));
+      cough_and_die (call_ptr);
+    } else {
+      fprintf (stdout, "%s: cannot handle Call[%li] (%i)\n",
+               __FUNCTION__, get_irn_node_nr (call),
+               get_SymConst_kind (call_ptr));
+      cough_and_die (call_ptr);
+    }
+  }
+
+  tp = get_entity_type (ent);
+  assert (is_Method_type (tp));
+
+  tp = get_method_res_type (tp, 0);
+
+  while (is_Pointer_type (tp)) {
+    tp = get_pointer_points_to_type (tp);
+  }
+
+  res = ta_type (tp);
+
+  return (res);
+}
+
+
+/**
+   Find an approximation to the given load node's value's types
+*/
+static typalise_t *typalise_load (ir_node *load)
+{
+  ir_entity *ent = NULL;
+  ir_type *tp = NULL;
+  typalise_t *res = NULL;
+  ir_node *load_ptr = get_Load_ptr (load);
+
+  if (iro_Sel == get_irn_opcode (load_ptr)) {
+    ent = get_Sel_entity (load_ptr);
+  } else if (iro_SymConst == get_irn_opcode (load_ptr)) {
+    if (get_SymConst_kind (load_ptr) == symconst_addr_ent) {
+      ent = get_SymConst_entity (load_ptr);
+    } else if (get_SymConst_kind (load_ptr) == symconst_type_tag) {
+      tp = get_SymConst_type (load_ptr);
+    } else {
+      fprintf (stdout, "%s: cannot handle load (%s)\n",
+               __FUNCTION__, get_op_name (get_irn_op (load_ptr)));
+
+      cough_and_die (load_ptr);
+    }
+  } else {
+    fprintf (stdout, "%s: cannot handle load (%s)\n",
+             __FUNCTION__, get_op_name (get_irn_op (load_ptr)));
+      cough_and_die (load_ptr);
+  }
+
+  tp = get_entity_type (ent);
+
+  while (is_Pointer_type (tp)) {
+    tp = get_pointer_points_to_type (tp);
+  }
+
+  res = ta_type (tp);
+
+  return (res);
+}
+
+
 /**
     Find an approximation to the given proj node's value's types
 */
@@ -466,43 +622,32 @@ static typalise_t *typalise_proj (ir_node *proj)
 
     proj_in = get_Proj_pred (proj_in);
     if (iro_Start == get_irn_opcode (proj_in)) {
-      ir_graph *graph = get_irn_irg (proj);
-      entity   *meth  = get_irg_entity (graph);
+      /* aha, proj arg */
+      ir_graph  *graph = get_irn_irg (proj);
+      ir_entity *meth  = get_irg_entity (graph);
 
       long n = get_Proj_proj (proj);
+      ir_type *tp = get_method_param_type (get_entity_type (meth), n);
+      if (is_Pointer_type (tp)) {
+        tp = get_pointer_points_to_type (tp);
+      }
 
-      if (1 == n) {
-        /* yay proj this */
-        type     *tp    = get_entity_owner (meth);
-
-        /* res = ta_exact (tp); */
-        res = ta_type (tp);     /* TODO */
-      } else {
-        /* ugh proj arg */
-        type *tp = get_method_param_type (get_entity_type (meth), n);
-        if (is_Pointer_type (tp)) {
-          tp = get_pointer_points_to_type (tp);
-        }
+      res = ta_type (tp);
 
-        res = ta_type (tp);
-      }
     } else if (iro_Call == get_irn_opcode (proj_in)) {
       /* call result ... 'whatever' */
-      /* hey, this is redundant (or the check for iro_Call further down) */
-      ir_node *call_ptr = get_Call_ptr (proj_in);
-
-      res = typalise (call_ptr);
+      res = typalise_call (proj_in);
     } else {
       fprintf (stdout, "\n Proj (Proj (%s)) not handled\n",
                get_op_name (get_irn_op (proj_in)));
-      assert (0);
+      cough_and_die (proj_in);
     }
   } else {
-    opcode op = get_irn_opcode (proj_in);
+    ir_opcode op = get_irn_opcode (proj_in);
     if ((iro_Load != op) && (iro_Alloc != op) && (iro_Call != op)) {
       fprintf (stdout, "\n Proj (%s) not handled\n",
                get_op_name (get_irn_op (proj_in)));
-      assert (0);
+      cough_and_die (proj_in);
     }
     res = typalise (proj_in);      /* everything else */
     /* Proj (Load), Proj (New), Proj (Call) */
@@ -545,14 +690,14 @@ lset_t *filter_for_ta (lset_t *set, typalise_t *ta)
 */
 typalise_t *typalise (ir_node *node)
 {
-  opcode op = get_irn_opcode (node);
+  ir_opcode op = get_irn_opcode (node);
   typalise_t *res = NULL;
 
   switch (op) {
   case (iro_Cast): {
     /* casts always succeed */
     typalise_t *ta = NULL;
-    type *tp = get_Cast_type (node);
+    ir_type *tp = get_Cast_type (node);
 
     if (is_Pointer_type (tp)) {
       tp = get_pointer_points_to_type (tp);
@@ -585,18 +730,18 @@ typalise_t *typalise (ir_node *node)
   } break;
 
   case (iro_Load): {
-    ir_node *load_ptr = get_Load_ptr (node);
-
-    res = typalise (load_ptr);
+    res = typalise_load (node);
   } break;
 
   case (iro_Sel): {
     /* FILTER */
     /* it's call (sel (ptr)) or load (sel (ptr)) */
-    entity *ent = get_Sel_entity (node);
-    type *tp = get_entity_type (ent);
+    ir_entity *ent = get_Sel_entity (node);
+    ir_type *tp = get_entity_type (ent);
 
     if (is_Method_type (tp)) {
+      /* obsoleted by typalise_call */
+      assert (0);
       tp = get_entity_type (ent);
       tp = get_method_res_type (tp, 0);
 
@@ -626,25 +771,30 @@ typalise_t *typalise (ir_node *node)
     int i;
     ir_node *phi_in = NULL;
     typalise_t *ta = NULL;
-    /* assert (0 && "Do we ever get here?"); */ /* apparently, we do. */
 
     for (i = 0; i < n_ins; i ++) {
+      typalise_t *ta_in;
+
       phi_in = get_irn_n (node, i);
-      ta = (NULL == ta) ? typalise (phi_in) : ta_join (ta, typalise (phi_in));
+      ta_in = typalise (phi_in);
+
+      if (NULL != ta_in) {
+        ta = (NULL == ta) ? ta_in : ta_join (ta, ta_in);
+      }
     }
 
     res = ta;
   } break;
 
   case (iro_Alloc): {
-    type *type = get_Alloc_type (node);
+    ir_type *type = get_Alloc_type (node);
     res = ta_exact (type);
   } break;
 
   case (iro_Call): {
     /* presumably call (sel (proj (call))) */
     ir_node *ptr = get_Call_ptr (node);
-    entity *meth = NULL;
+    ir_entity *meth = NULL;
     if (iro_Sel == get_irn_opcode (ptr)) {
       meth = get_Sel_entity (ptr);
     } else if (iro_SymConst == get_irn_opcode (ptr)) {
@@ -656,7 +806,7 @@ typalise_t *typalise (ir_node *node)
     }
 
     if (NULL != meth) {
-      type *tp = get_method_res_type ((type*) meth, 0);
+      ir_type *tp = get_method_res_type ((ir_type*) meth, 0);
       res = ta_type (tp);
     } else {
       /* could be anything */
@@ -664,50 +814,99 @@ typalise_t *typalise (ir_node *node)
       res = NULL;
     }
 
-    fprintf (stdout, "]\n");
+    /* fprintf (stdout, "]\n"); */
 
   } break;
 
   case (iro_SymConst): {
     if (get_SymConst_kind (node) == symconst_type_tag) {
-      type *tp = get_SymConst_type (node);
+      ir_type *tp = get_SymConst_type (node);
 
       res = ta_type (tp);
     } else if (get_SymConst_kind (node) == symconst_addr_ent) {
-      entity *ent = get_SymConst_entity (node);
-      type *tp = get_entity_type (ent);
-      tp = get_pointer_points_to_type (tp);
+      ir_entity *ent = get_SymConst_entity (node);
+      ir_type *tp = get_entity_owner (ent);
+
+      while (is_Pointer_type (tp)) {
+        tp = get_pointer_points_to_type (tp);
+      }
+
       assert (is_Class_type (tp));
 
       res = ta_type (tp);       /* can't use ta_exact */
+    } else if (get_SymConst_kind (node) == symconst_addr_name) {
+      /* oh, this is not a real call but a placeholder (exception stuff) */
+      fprintf (stdout, "%s (%s:%i): can't handle pseudo-call %s\n",
+               __FUNCTION__, __FILE__, __LINE__,
+               get_op_name (get_irn_op (node)));
+
+      res = NULL;
     } else {
-      fprintf (stdout, "%s (%s:%i): can't handle SymConst %s?\n",
+      fprintf (stdout, "%s (%s:%i): can't handle SymConst %s\n",
                __FUNCTION__, __FILE__, __LINE__,
                get_op_name (get_irn_op (node)));
+
       res = NULL;
     }
   } break;
+  case (iro_Const): {
+    /* presumably a NULL constant */
+    /* this also means we cannot handle calls against a NULL pointer. */
+    res = NULL;
+  } break;
 
-  /* template:
-     case (iro_Cast): {}
-     break;
-  */
+    /* template:
+       case (iro_Cast): {}
+       break;
+    */
 
   default: {
     fprintf (stdout, "what's with %s?\n", get_op_name (get_irn_op (node)));
-    assert (0);
+    cough_and_die (node);
   } break;
   }
 
   return (res);
 }
 
+/*
+  Initialise the Typalise module
+*/
+void typalise_init (void)
+{
+  if (NULL == java_lang_Throwable_tp) {
+    class_walk_super2sub (find_java_lang_Throwable, NULL, NULL);
+
+    /* make sure we have found it */
+    get_java_lang_Throwable ();
+  }
+}
 
 
 
 \f
 /*
   $Log$
+  Revision 1.14  2007/01/16 15:45:42  beck
+  renamed type opcode to ir_opcode
+
+  Revision 1.13  2006/12/13 19:46:47  beck
+  rename type entity into ir_entity
+
+  Revision 1.12  2006/01/13 21:54:02  beck
+  renamed all types 'type' to 'ir_type'
+
+  Revision 1.11  2005/05/13 16:35:14  beck
+  made (void) prototypes
+  removed unused fprintf arguments
+
+  Revision 1.10  2005/05/06 12:02:34  beck
+  added missing includes
+  removed C99 features
+
+  Revision 1.9  2005/03/22 13:56:09  liekweg
+  "small" fix for exception b/d
+
   Revision 1.8  2005/01/14 14:13:24  liekweg
   fix gnu extension