fixed copy'n'paste error
[libfirm] / ir / opt / funccall.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/opt/ldstopt.c
4  * Purpose:     optimization of function calls
5  * Author:
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 } env_t;
30
31 /**
32  * remove memory from real function calls by rerouting
33  * it's ProjM and connection the call with a NoMem node.
34  *
35  * Note: By "real function" we understand a function that did neither
36  * read nor write memory.
37  */
38 static void rem_mem_from_real_fkt_calls(ir_node *node, void *env)
39 {
40   env_t *ctx = env;
41   ir_node *call, *ptr, *mem;
42   entity *ent;
43
44   if (get_irn_op(node) != op_Proj || get_irn_mode(node) != mode_M)
45     return;
46
47   /* look at Memory Proj's */
48   call = get_Proj_pred(node);
49   if (get_irn_op(call) != op_Call)
50     return;
51
52   ptr = get_Call_ptr(call);
53   if (get_irn_op(ptr) != op_SymConst || get_SymConst_kind(ptr) != symconst_addr_ent)
54     return;
55
56   ent = get_SymConst_entity(ptr);
57
58   if (! eset_contains(ctx->pure_fkt, ent))
59     return;
60
61   /* ok, if we get here we found a call to a pure function,
62    * route the NoMem node to the call */
63   mem   = get_Call_mem(call);
64
65   exchange(node, mem);
66   set_Call_mem(call, new_r_NoMem(current_ir_graph));
67
68   /* finally, this call can floats */
69   set_irn_pinned(call, op_pin_state_floats);
70
71   hook_func_call(current_ir_graph, call);
72
73   ctx->changed = 1;
74 }
75
76 /*
77  * optimize function calls by handling real functions
78  */
79 void optimize_funccalls(void)
80 {
81   int i, n, j, k;
82   int change;
83   unsigned num_pure = 0;
84   eset *pure_fkt = eset_create();
85
86   if (! get_opt_real_func_call())
87     return;
88
89   /* first step: detect, which functions are pure, ie do NOT change any memory */
90   for (i = 0, n = get_irp_n_irgs(); i < n; ++i) {
91     ir_graph *irg  = get_irp_irg(i);
92     ir_node *end   = get_irg_end(irg);
93     ir_node *endbl = get_nodes_block(end);
94
95     change = 0;
96
97     /* visit every Return */
98     for (j = 0, k = get_Block_n_cfgpreds(endbl); j < k; ++j) {
99       ir_node *node = get_Block_cfgpred(endbl, j);
100       ir_op   *op   = get_irn_op(node);
101       ir_node *mem;
102
103       /* Bad nodes usually do NOT produce anything, so it's ok */
104       if (op == op_Bad)
105         continue;
106
107       if (op == op_Return) {
108         mem = get_Return_mem(node);
109
110         /* Bad nodes usually do NOT produce anything, so it's ok */
111         if (is_Bad(mem))
112           continue;
113
114         change = mem != get_irg_initial_mem(irg);
115         if (change)
116           break;
117       }
118       else {
119         /* exception found */
120         change = 1;
121         break;
122       }
123     }
124
125     if (! change) {
126       /* check, if a keep-alive exists */
127       for (j = 0, k = get_End_n_keepalives(end); j < k; ++j) {
128         ir_node *mem = get_End_keepalive(end, j);
129
130         if (mode_M != get_irn_mode(mem))
131           continue;
132
133         change = mem != get_irg_initial_mem(irg);
134         if (change)
135           break;
136       }
137     }
138
139     if (! change) {
140       eset_insert(pure_fkt, get_irg_entity(irg));
141       ++num_pure;
142     }
143   }
144
145   if (num_pure > 0) {
146     env_t ctx;
147
148     ctx.pure_fkt = pure_fkt;
149
150     /* all calls of pure functions can be transformed into FuncCalls */
151     for (i = 0, n = get_irp_n_irgs(); i < n; ++i) {
152       ir_graph *irg  = get_irp_irg(i);
153
154       ctx.changed = 0;
155       irg_walk_graph(irg, NULL, rem_mem_from_real_fkt_calls, &ctx);
156
157       if (ctx.changed) {
158         /* changes were done */
159         set_irg_outs_inconsistent(irg);
160         set_irg_loopinfo_state(current_ir_graph, loopinfo_cf_inconsistent);
161       }
162     }
163   }
164
165   eset_destroy(pure_fkt);
166 }