added configure stuff
[libfirm] / ir / opt / funccall.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/opt/funccall.c
4  * Purpose:     optimization of function calls
5  * Author:      Michael Beck
6  * Created:
7  * CVS-ID:      $Id$
8  * Copyright:   (c) 1998-2004 Universit�t Karlsruhe
9  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
10  */
11 #include "irnode_t.h"
12 #include "irgraph_t.h"
13 #include "irgmod.h"
14 #include "irgwalk.h"
15 #include "irvrfy.h"
16 #include "dbginfo_t.h"
17 #include "irflag_t.h"
18 #include "ircons.h"
19 #include "funccall.h"
20 #include "irhooks.h"
21
22 /**
23  * The walker environment for rem_mem_from_const_fkt_calls
24  */
25 typedef struct _env_t {
26   int  changed;                   /**< flag, is set if a graph was changed */
27   int  n_calls_removed_SymConst;
28   int  n_calls_removed_Sel;
29 } env_t;
30
31 /**
32  * remove memory from const function calls by rerouting
33  * it's ProjM and connection the call with a NoMem node.
34  *
35  * Note: By "const function" we understand a function that did neither
36  * read nor write memory. Hence its result depends solely on its
37  * arguments.
38  */
39 static void rem_mem_from_const_fkt_calls(ir_node *node, void *env)
40 {
41   env_t *ctx = env;
42   ir_node *call, *ptr, *mem;
43   entity *ent;
44
45   if (get_irn_op(node) == op_Call) {
46     call = node;
47
48     set_irn_link(call, NULL);
49
50     ptr = get_Call_ptr(call);
51     if (get_irn_op(ptr) == op_SymConst && get_SymConst_kind(ptr) == symconst_addr_ent) {
52
53       ent = get_SymConst_entity(ptr);
54
55       if ((get_entity_additional_properties(ent) & irg_const_function) == 0)
56         return;
57       ++ctx->n_calls_removed_SymConst;
58     }
59     else if (get_irn_op(ptr) == op_Sel &&
60              get_irg_callee_info_state(current_ir_graph) == irg_callee_info_consistent) {
61       /* If all possible callees are real functions, we can remove the memory edge. */
62       int i, n_callees = get_Call_n_callees(call);
63       if (n_callees == 0)
64         /* This is kind of strange:  dying code or a Call that will raise an exception
65                  when executed as there is no implementation to call.  So better not
66                  optimize. */
67         return;
68       for (i = 0; i < n_callees; ++i) {
69         ent = get_Call_callee(call, i);
70         if ((get_entity_additional_properties(ent) & irg_const_function) == 0)
71                 return;
72       }
73       ++ctx->n_calls_removed_Sel;
74     }
75     else
76       return;
77
78     /* ok, if we get here we found a call to a const function,
79      * route the NoMem node to the call */
80     mem   = get_Call_mem(call);
81
82     set_irn_link(call, mem);
83     set_Call_mem(call, new_r_NoMem(current_ir_graph));
84
85     /* finally, this call can float */
86     set_irn_pinned(call, op_pin_state_floats);
87
88     hook_func_call(current_ir_graph, call);
89
90     ctx->changed = 1;
91   }
92   else if (get_irn_op(node) == op_Proj) {
93     /*
94      * Remove memory and exception Proj's from
95      * const function calls.
96      */
97     call = get_Proj_pred(node);
98     if ((get_irn_op(call) != op_Call) ||
99         (get_irn_op(get_Call_mem(call)) != op_NoMem))
100       return;
101
102     switch (get_Proj_proj(node)) {
103     case pn_Call_M_regular: {
104       ir_node *old_mem = get_irn_link(call);
105       if (old_mem)
106         exchange(node, old_mem);
107     } break;
108     case pn_Call_X_except:
109     case pn_Call_M_except:
110       exchange(node, new_Bad());
111       break;
112     default: ;
113     }
114   }
115 }
116
117 /*
118  * optimize function calls by handling const functions
119  */
120 void optimize_funccalls(int force_run)
121 {
122   int i, j;
123   int change;
124   unsigned num_pure = 0;
125
126   if (! get_opt_real_func_call())
127     return;
128
129   /* first step: detect, which functions are const, i.e. do NOT touch any memory */
130   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
131     ir_graph *irg  = get_irp_irg(i);
132     ir_node *end   = get_irg_end(irg);
133     ir_node *endbl = get_nodes_block(end);
134
135     change = 0;
136
137     if (get_irg_additional_properties(irg) & irg_const_function) {
138       /* already marked as a const function */
139       ++num_pure;
140     }
141     else {
142       /* visit every Return */
143       for (j = get_Block_n_cfgpreds(endbl) - 1; j >= 0; --j) {
144         ir_node *node = get_Block_cfgpred(endbl, j);
145         ir_op   *op   = get_irn_op(node);
146         ir_node *mem;
147
148         /* Bad nodes usually do NOT produce anything, so it's ok */
149         if (op == op_Bad)
150           continue;
151
152         if (op == op_Return) {
153           mem = get_Return_mem(node);
154
155           /* Bad nodes usually do NOT produce anything, so it's ok */
156           if (is_Bad(mem))
157             continue;
158
159           change = mem != get_irg_initial_mem(irg);
160           if (change)
161             break;
162         }
163         else {
164           /* exception found */
165           change = 1;
166           break;
167         }
168       }
169
170       if (! change) {
171         /* check, if a keep-alive exists */
172         for (j = get_End_n_keepalives(end) - 1; j >= 0; --j) {
173           ir_node *mem = get_End_keepalive(end, j);
174
175           if (mode_M != get_irn_mode(mem))
176             continue;
177
178           change = mem != get_irg_initial_mem(irg);
179           if (change)
180             break;
181         }
182       }
183
184       if (! change) {
185         /* no memory changes found, it's a const function */
186         set_irg_additional_property(irg, irg_const_function);
187         ++num_pure;
188       }
189     }
190   }
191
192   if (force_run || num_pure > 0) {
193     env_t ctx;
194
195     ctx.n_calls_removed_SymConst = 0;
196     ctx.n_calls_removed_Sel = 0;
197
198     /* all calls of pure functions can be transformed into FuncCalls */
199     for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
200       ir_graph *irg  = get_irp_irg(i);
201
202       /* no need to do this on const functions */
203       if ((get_irg_additional_properties(irg) & irg_const_function) == 0) {
204         ctx.changed = 0;
205         irg_walk_graph(irg, NULL, rem_mem_from_const_fkt_calls, &ctx);
206
207         if (ctx.changed) {
208           /* changes were done */
209           set_irg_outs_inconsistent(irg);
210           set_irg_loopinfo_state(current_ir_graph, loopinfo_cf_inconsistent);
211         }
212       }
213     }
214
215     if (get_firm_verbosity()) {
216       printf("Detected %d graphs without side effects.\n", num_pure);
217       printf("Optimizes %d(SymConst) + %d(Sel) calls to const functions.\n",
218              ctx.n_calls_removed_SymConst, ctx.n_calls_removed_Sel);
219     }
220   }
221   else {
222     if (get_firm_verbosity()) {
223       printf("No graphs without side effects detected\n");
224     }
225   }
226 }
227
228 /**
229  * Walker: Walks over all graphs and evaluates calls with
230  * constant arguments.
231  * Currently used only for non-virtual calls.
232  */
233 static void eval_calls(ir_node *call, void *env)
234 {
235   ir_node  *ptr, *param;
236   entity   *ent;
237   ir_graph *irg;
238   int      i;
239
240   if (get_irn_op(call) != op_Call)
241     return;
242
243   ptr = get_Call_ptr(call);
244
245   if (get_irn_op(ptr) != op_SymConst)
246     return;
247
248   if (get_SymConst_kind(ptr) != symconst_addr_ent)
249     return;
250
251   ent = get_SymConst_entity(ptr);
252   irg = get_entity_irg(ent);
253
254   if (! irg)
255     return;
256
257   /* ok, we found the called graph here, check for const args */
258   for (i = get_Call_n_params(call) - 1; i >= 0; --i) {
259     param = get_Call_param(call, i);
260
261     if (is_irn_constlike(param)) {
262       /* Found one: add to statistics */
263
264       ir_printf("%+F called with const %+F at position %d\n", ent, param, i);
265     }
266   }
267 }