df717ec6dcdd37399621134bbbdcdab58c35bf80
[libfirm] / ir / opt / funccall.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/opt/ldstopt.c
4  * Purpose:     optimization of function calls
5  * Author:      Michael M. 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 "eset.h"
20 #include "funccall.h"
21 #include "irhooks.h"
22
23 /**
24  * The walker environment for rem_mem_from_real_fkt_calls
25  */
26 typedef struct _env_t {
27   eset *pure_fkt;   /**< set containing all real functions */
28   int  changed;     /**< flag, is set if a graph was changed */
29   int  n_calls_removed_SymConst;
30   int  n_calls_removed_Sel;
31 } env_t;
32
33 /**
34  * remove memory from real function calls by rerouting
35  * it's ProjM and connection the call with a NoMem node.
36  *
37  * Note: By "real function" we understand a function that did neither
38  * read nor write memory.
39  */
40 static void rem_mem_from_real_fkt_calls(ir_node *node, void *env)
41 {
42   env_t *ctx = env;
43   ir_node *call, *ptr, *mem;
44   entity *ent;
45
46   if (get_irn_op(node) == op_Call) {
47     call = node;
48
49     set_irn_link(call, NULL);
50
51     ptr = get_Call_ptr(call);
52     if (get_irn_op(ptr) == op_SymConst && get_SymConst_kind(ptr) == symconst_addr_ent) {
53
54       ent = get_SymConst_entity(ptr);
55
56       if (! eset_contains(ctx->pure_fkt, ent))
57         return;
58       ctx->n_calls_removed_SymConst++;
59     }
60     else if (get_irn_op(ptr) == op_Sel &&
61              get_irg_callee_info_state(current_ir_graph) == irg_callee_info_consistent) {
62       /* If all possible callees are real functions, we can remove the memory edge. */
63       int i, n_callees = get_Call_n_callees(call);
64       if (n_callees == 0)
65         /* This is kind of strange:  dying code or a Call that will raise an exception
66            when executed as there is no implementation to call.  So better not
67            optimize. */
68         return;
69       for (i = 0; i < n_callees; ++i) {
70         if (! eset_contains(ctx->pure_fkt, get_Call_callee(call, i)))
71           return;
72       }
73       ctx->n_calls_removed_Sel++;
74     }
75     else return;
76
77     /* ok, if we get here we found a call to a pure function,
78      * route the NoMem node to the call */
79     mem   = get_Call_mem(call);
80
81     set_irn_link(call, mem);
82     set_Call_mem(call, new_r_NoMem(current_ir_graph));
83
84     /* finally, this call can float */
85     set_irn_pinned(call, op_pin_state_floats);
86
87     hook_func_call(current_ir_graph, call);
88
89     ctx->changed = 1;
90   } else if (get_irn_op(node) == op_Proj) {
91     call = get_Proj_pred(node);
92     if ((get_irn_op(call) != op_Call) ||
93         (get_irn_op(get_Call_mem(call)) != op_NoMem))
94       return;
95
96     switch(get_Proj_proj(node)) {
97     case pn_Call_M_regular: {
98       ir_node *old_mem = get_irn_link(call);
99       if (old_mem) exchange(node, old_mem);
100     } break;
101     case pn_Call_X_except:
102     case pn_Call_M_except:
103       exchange(node, new_Bad());
104       break;
105     default: ;
106     }
107   }
108 }
109
110 /*
111  * optimize function calls by handling real functions
112  */
113 void optimize_funccalls(void)
114 {
115   int i, n, j, k;
116   int change;
117   unsigned num_pure = 0;
118   eset *pure_fkt = eset_create();
119
120   if (! get_opt_real_func_call())
121     return;
122
123   /* first step: detect, which functions are pure, i.e. do NOT change any memory */
124   for (i = 0, n = get_irp_n_irgs(); i < n; ++i) {
125     ir_graph *irg  = get_irp_irg(i);
126     ir_node *end   = get_irg_end(irg);
127     ir_node *endbl = get_nodes_block(end);
128
129     change = 0;
130
131     /* visit every Return */
132     for (j = 0, k = get_Block_n_cfgpreds(endbl); j < k; ++j) {
133       ir_node *node = get_Block_cfgpred(endbl, j);
134       ir_op   *op   = get_irn_op(node);
135       ir_node *mem;
136
137       /* Bad nodes usually do NOT produce anything, so it's ok */
138       if (op == op_Bad)
139         continue;
140
141       if (op == op_Return) {
142         mem = get_Return_mem(node);
143
144         /* Bad nodes usually do NOT produce anything, so it's ok */
145         if (is_Bad(mem))
146           continue;
147
148         change = mem != get_irg_initial_mem(irg);
149         if (change)
150           break;
151       }
152       else {
153         /* exception found */
154         change = 1;
155         break;
156       }
157     }
158
159     if (! change) {
160       /* check, if a keep-alive exists */
161       for (j = 0, k = get_End_n_keepalives(end); j < k; ++j) {
162         ir_node *mem = get_End_keepalive(end, j);
163
164         if (mode_M != get_irn_mode(mem))
165           continue;
166
167         change = mem != get_irg_initial_mem(irg);
168         if (change)
169           break;
170       }
171     }
172
173     if (! change) {
174       eset_insert(pure_fkt, get_irg_entity(irg));
175       ++num_pure;
176     }
177   }
178
179   if (num_pure > 0) {
180     env_t ctx;
181     entity *ent;
182
183     ctx.pure_fkt = pure_fkt;
184     ctx.n_calls_removed_SymConst = 0;
185     ctx.n_calls_removed_Sel = 0;
186
187     /* all calls of pure functions can be transformed into FuncCalls */
188     for (i = 0, n = get_irp_n_irgs(); i < n; ++i) {
189       ir_graph *irg  = get_irp_irg(i);
190
191       ctx.changed = 0;
192       irg_walk_graph(irg, NULL, rem_mem_from_real_fkt_calls, &ctx);
193
194       if (ctx.changed) {
195         /* changes were done */
196         set_irg_outs_inconsistent(irg);
197         set_irg_loopinfo_state(current_ir_graph, loopinfo_cf_inconsistent);
198       }
199     }
200
201     if (get_firm_verbosity()) {
202       printf("Detected %d functions without side effects.\n", num_pure);
203       printf("Optimizes %d(SymConst) + %d(Sel) calls to these functions.\n",
204              ctx.n_calls_removed_SymConst, ctx.n_calls_removed_Sel);
205       if (get_firm_verbosity() > 1) {
206         for (ent = eset_first(pure_fkt); ent; ent = eset_next(pure_fkt)) {
207           printf("  "); DDMEO(ent);
208         }
209       }
210     }
211
212   } else {
213     if (get_firm_verbosity()) {
214       printf("No functions without side effects detected\n");
215     }
216   }
217
218   eset_destroy(pure_fkt);
219 }