9de651f3fd339a34dfebed3ac94683270b1c5153
[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  n_calls_removed_SymConst;
27   int  n_calls_removed_Sel;
28   ir_node *list;                  /**< The list of all Calls that will be changed. */
29   ir_node *proj_list;             /**< list of all potential Proj nones that must be fixed.*/
30 } env_t;
31
32 /**
33  * remove memory from const function calls by rerouting
34  * it's ProjM and connection the call with a NoMem node.
35  *
36  * Note: By "const function" we understand a function that did neither
37  * read nor write memory. Hence its result depends solely on its
38  * arguments.
39  */
40 static void rem_mem_from_const_fkt_calls(ir_node *node, void *env)
41 {
42   env_t *ctx = env;
43   ir_node *call, *ptr;
44   entity *ent;
45
46   if (get_irn_op(node) == op_Call) {
47     call = node;
48
49     set_irn_link(call, NULL);
50     ptr = get_Call_ptr(call);
51     if (get_irn_op(ptr) == op_SymConst && get_SymConst_kind(ptr) == symconst_addr_ent) {
52       ent = get_SymConst_entity(ptr);
53
54       if ((get_entity_additional_properties(ent) & mtp_property_const) == 0)
55         return;
56       ++ctx->n_calls_removed_SymConst;
57     }
58     else if (is_Sel(ptr) &&
59              get_irg_callee_info_state(current_ir_graph) == irg_callee_info_consistent) {
60       /* If all possible callees are real functions, we can remove the memory edge. */
61       int i, n_callees = get_Call_n_callees(call);
62       if (n_callees == 0)
63         /* This is kind of strange:  dying code or a Call that will raise an exception
64                  when executed as there is no implementation to call.  So better not
65                  optimize. */
66         return;
67       for (i = 0; i < n_callees; ++i) {
68         ent = get_Call_callee(call, i);
69         if (ent == unknown_entity) {
70           /* we don't know which entity is called here */
71           return;
72         }
73         if ((get_entity_additional_properties(ent) & mtp_property_const) == 0)
74           return;
75       }
76       ++ctx->n_calls_removed_Sel;
77     }
78     else
79       return;
80
81     /* ok, if we get here we found a call to a const function */
82     set_irn_link(call, ctx->list);
83     ctx->list = call;
84   }
85   else if (get_irn_op(node) == op_Proj) {
86     /*
87      * Collect all memory and exception Proj's from
88      * calls.
89      */
90     call = get_Proj_pred(node);
91     if (get_irn_op(call) != op_Call)
92       return;
93
94     switch (get_Proj_proj(node)) {
95     case pn_Call_M_regular:
96     case pn_Call_X_except:
97     case pn_Call_M_except:
98       set_irn_link(node, ctx->proj_list);
99       ctx->proj_list = node;
100       break;
101     default:
102       ;
103     }
104   }
105 }
106
107 /**
108  * Fix the list of collected Calls.
109  */
110 static void fix_call_list(ir_graph *irg, ir_node *call_list, ir_node *proj_list) {
111   ir_node *call, *next, *mem, *proj;
112   int exc_changed = 0;
113
114   /* fix all calls by removing it's memory input */
115   for (call = call_list; call; call = next) {
116     next = get_irn_link(call);
117     mem  = get_Call_mem(call);
118
119     set_irn_link(call, mem);
120     set_Call_mem(call, get_irg_no_mem(irg));
121
122     /* finally, this call can float */
123     set_irn_pinned(call, op_pin_state_floats);
124     hook_func_call(irg, call);
125   }
126
127   /* finally fix all Proj's */
128   for (proj = proj_list; proj; proj = next) {
129     next = get_irn_link(proj);
130     call = get_Proj_pred(proj);
131     mem  = get_irn_link(call);
132     if (! mem)
133       continue;
134
135     switch (get_Proj_proj(proj)) {
136     case pn_Call_M_regular: {
137       exchange(proj, mem);
138     } break;
139     case pn_Call_X_except:
140     case pn_Call_M_except:
141       exc_changed = 1;
142       exchange(proj, get_irg_bad(irg));
143       break;
144     default:
145       ;
146     }
147   }
148
149   /* changes were done ... */
150   set_irg_outs_inconsistent(irg);
151   set_irg_loopinfo_state(current_ir_graph, loopinfo_cf_inconsistent);
152
153   if (exc_changed) {
154     /* ... including exception edges */
155     set_irg_doms_inconsistent(irg);
156   }
157 }
158
159 /*
160  * optimize function calls by handling const functions
161  */
162 void optimize_funccalls(int force_run)
163 {
164   int i, j;
165   int change;
166   unsigned num_pure = 0;
167
168   if (! get_opt_real_function_call())
169     return;
170
171   /* first step: detect, which functions are const, i.e. do NOT touch any memory */
172   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
173     ir_graph *irg  = get_irp_irg(i);
174     ir_node *end   = get_irg_end(irg);
175     ir_node *endbl = get_nodes_block(end);
176
177     change = 0;
178
179     if (get_irg_additional_properties(irg) & mtp_property_const) {
180       /* already marked as a const function */
181       ++num_pure;
182     }
183     else {
184       /* visit every Return */
185       for (j = get_Block_n_cfgpreds(endbl) - 1; j >= 0; --j) {
186         ir_node *node = get_Block_cfgpred(endbl, j);
187         ir_op   *op   = get_irn_op(node);
188         ir_node *mem;
189
190         /* Bad nodes usually do NOT produce anything, so it's ok */
191         if (op == op_Bad)
192           continue;
193
194         if (op == op_Return) {
195           mem = get_Return_mem(node);
196
197           /* Bad nodes usually do NOT produce anything, so it's ok */
198           if (is_Bad(mem))
199             continue;
200
201           change = mem != get_irg_initial_mem(irg);
202           if (change)
203             break;
204         }
205         else {
206           /* exception found */
207           change = 1;
208           break;
209         }
210       }
211
212       if (! change) {
213         /* check, if a keep-alive exists */
214         for (j = get_End_n_keepalives(end) - 1; j >= 0; --j) {
215           ir_node *mem = get_End_keepalive(end, j);
216
217           if (mode_M != get_irn_mode(mem))
218             continue;
219
220           change = mem != get_irg_initial_mem(irg);
221           if (change)
222             break;
223         }
224       }
225
226       if (! change) {
227         /* no memory changes found, it's a const function */
228         set_irg_additional_property(irg, mtp_property_const);
229         ++num_pure;
230       }
231     }
232   }
233
234   if (force_run || num_pure > 0) {
235     env_t ctx;
236
237     ctx.n_calls_removed_SymConst = 0;
238     ctx.n_calls_removed_Sel = 0;
239
240     /* all calls of pure functions can be transformed into FuncCalls */
241     for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
242       ir_graph *irg  = get_irp_irg(i);
243
244       /* no need to do this on const functions */
245       if ((get_irg_additional_properties(irg) & mtp_property_const) == 0) {
246         ctx.list      = NULL;
247         ctx.proj_list = NULL;
248         irg_walk_graph(irg, NULL, rem_mem_from_const_fkt_calls, &ctx);
249
250         if (ctx.list)
251           fix_call_list(irg, ctx.list, ctx.proj_list);
252       }
253     }
254
255     if (get_firm_verbosity()) {
256       printf("Detected %d graphs without side effects.\n", num_pure);
257       printf("Optimizes %d(SymConst) + %d(Sel) calls to const functions.\n",
258              ctx.n_calls_removed_SymConst, ctx.n_calls_removed_Sel);
259     }
260   }
261   else {
262     if (get_firm_verbosity()) {
263       printf("No graphs without side effects detected\n");
264     }
265   }
266 }