599b1444812f2d56dd4a9026bcfe3739f1e68337
[libfirm] / ir / opt / proc_cloning.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/opt/proc_cloning.c
4  * Purpose:     procedure cloning
5  * Author:      Beyhan Veliev
6  * Created:
7  * CVS-ID:      $Id$
8  * Copyright:   (c) 1998-2005 Universität Karlsruhe
9  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
10  */
11
12 /**
13  * @file proc_cloning.c
14  *
15  */
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19
20 #include <stdarg.h>
21 #include <string.h>
22
23 #include "tv.h"
24 #include "set.h"
25 #include "entity.h"
26 #include "irprog_t.h"
27 #include "hashptr.h"
28 #include "irgwalk.h"
29 #include "proc_cloning.h"
30 #include "analyze_irg_args.h"
31 #include "irprintf.h"
32
33 /* A macro to iterate sets.*/
34 #define ITERATE_SET(set_entrys, entry) for(entry = set_first(set_entrys); entry; entry = set_next(set_entrys))
35
36 /**
37  * This struct contains the information triple for a Call, which we need to
38  * decide if this function must be cloned.
39  */
40 typedef struct _entry {
41   struct triple {
42     entity        *ent;   /**< The entity of our Call. */
43     int           pos;    /**< Position of a constant argument of our Call. */
44     tarval        *tv;    /**< The tarval of this constant argument. */
45   } t;                    /**< The heuristic triple. */
46
47   unsigned      num_calls;  /**< number of calls */
48   float         weight;     /**< The estimated weight of this triple. */
49   struct _entry *next;      /**< used for linking and sorting */
50 } entry_t;
51
52 /**
53  * Compare two triples.
54  *
55  * @return 0 if they are identically
56  */
57 static int entry_cmp(const void *elt, const void *key, size_t size)
58 {
59   const entry_t *c1 = elt;
60   const entry_t *c2 = key;
61
62   return (c1->t.ent != c2->t.ent) || (c1->t.pos != c2->t.pos) || (c1->t.tv != c2->t.tv);
63 }
64
65 /**
66  * Hash a element of typ entry_t
67  *
68  * @param name    A string (the name of the method)
69  * @param length  The length of this string
70  * @param pos     A integer value.
71  */
72 static int hash_entry(const entry_t *entry)
73 {
74   return HASH_PTR(entry->t.ent) ^ HASH_PTR(entry->t.tv) ^ (entry->t.pos * 9);
75 }
76
77 /**
78  * Collect all calls in a ir_graph
79  * to a set.
80  *
81  * @param call   A ir_node to be checked.
82  * @param env    The set where we will collect the calls.
83  */
84 static void collect_irg_calls(ir_node *call, void *env)
85 {
86   set *entrys = env;
87   ir_node *call_ptr;
88   entity *call_ent;
89   type *mtp;
90   entry_t key, *entry;
91   ir_node *call_param;
92   int i, n_params;
93
94   /* We collect just "Call" nodes*/
95   if (get_irn_op(call) != op_Call)
96     return;
97
98   call_ptr = get_Call_ptr(call);
99
100   /* Call pointer must be a symconst*/
101   if (op_SymConst != get_irn_op(call_ptr))
102     return;
103   /* Call pointer must be the address of an entity.*/
104   if (get_SymConst_kind(call_ptr) != symconst_addr_ent)
105     return;
106
107   call_ent = get_SymConst_entity(call_ptr);
108
109   /* we can only clone calls to existing entities */
110   if (get_entity_visibility(call_ent) == visibility_external_allocated)
111     return;
112
113   n_params = get_Call_n_params(call);
114
115   /* beware: we cannot clone variadic parameters */
116   mtp = get_Call_type(call);
117   if (get_method_variadicity(mtp) != variadicity_non_variadic) {
118     n_params = get_method_first_variadic_param_index(mtp);
119   }
120
121   /* In this for loop we collect the calls, that have
122      an constant parameter. */
123   for (i = n_params - 1; i >= 0; --i) {
124     call_param = get_Call_param(call, i);
125     if (is_Const(call_param)) {
126       /* we have found a Call to collect and we save the informations,
127          which we need.*/
128       key.t.ent     = call_ent;
129       key.t.pos     = i;
130       key.t.tv      = get_Const_tarval(call_param);
131       key.num_calls = 0;
132
133       /* We insert our information in the set, where we collect the calls.*/
134       entry     = set_insert(entrys, &key, sizeof(key), hash_entry(&key));
135
136       /* we found one more */
137       ++entry->num_calls;
138     }
139   }
140 }
141
142 /*
143  * Do the procedure cloning. Evaluate a heuristic weight for every
144  * call(..., Const, ...). If the weight is bigger than threshold,
145  * clone the entity and fix the calls.
146  */
147 void proc_cloning(float threshold)
148 {
149   set *set_entrys;
150   entry_t *entry, *p, *heavy_uses = NULL;
151   ir_graph *irg;
152   int i;
153
154   set_entrys  = new_set(entry_cmp, 8);
155   entry       = NULL;
156
157   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
158     irg = get_irp_irg(i);
159     irg_walk_graph(irg, collect_irg_calls, NULL, set_entrys);
160   }
161
162   /* We iterate the set and arrange the element of the set in a list.
163      The elements are arranged dependent of their value descending.*/
164   ITERATE_SET(set_entrys, entry) {
165     entry->weight = entry->num_calls *
166       (get_method_param_weight(entry->t.ent, entry->t.pos) + 1);
167
168     /*
169      * Do not put entry with a weight < threshold in the list
170      */
171     if (entry->weight < threshold)
172       continue;
173
174     /* put entry in the heavy uses list */
175     entry->next = NULL;
176     if (! heavy_uses)
177       heavy_uses = entry;
178     else {
179       if (entry->weight >= heavy_uses->weight) {
180         entry->next = heavy_uses;
181         heavy_uses  = entry;
182       }
183       else {
184         for (p = heavy_uses; p->next; p = p->next) {
185           if (entry->weight >= p->next->weight) {
186                   entry->next = p->next;
187             p->next     = entry;
188                   break;
189           }
190         }
191         if (! p->next)
192           p->next = entry;
193       }
194     }
195   }
196
197   /* Print some informations about the list. */
198   for (entry = heavy_uses; entry; entry = entry->next) {
199     printf("\nweight: is %f\n", entry->weight);
200     ir_printf("Call for Method %E\n", entry->t.ent);
201     printf("Position %i\n", entry->t.pos);
202     ir_printf("Value %T\n", entry->t.tv);
203     printf("Number of calls %u\n", entry->num_calls);
204     printf("est. nodes %u\n", get_irg_estimated_node_cnt(get_entity_irg(entry->t.ent)));
205   }
206 }