3 * File name: ir/opt/funccall.c
4 * Purpose: optimization of function calls
8 * Copyright: (c) 1998-2004 Universit�t Karlsruhe
9 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
12 #include "irgraph_t.h"
16 #include "dbginfo_t.h"
23 * The walker environment for rem_mem_from_const_fkt_calls
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;
32 * remove memory from const function calls by rerouting
33 * it's ProjM and connection the call with a NoMem node.
35 * Note: By "const function" we understand a function that did neither
36 * read nor write memory. Hence its result depends solely on its
39 static void rem_mem_from_const_fkt_calls(ir_node *node, void *env)
42 ir_node *call, *ptr, *mem;
45 if (get_irn_op(node) == op_Call) {
48 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) {
53 ent = get_SymConst_entity(ptr);
55 if ((get_entity_additional_properties(ent) & irg_const_function) == 0)
57 ++ctx->n_calls_removed_SymConst;
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);
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
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)
73 ++ctx->n_calls_removed_Sel;
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);
82 set_irn_link(call, mem);
83 set_Call_mem(call, new_r_NoMem(current_ir_graph));
85 /* finally, this call can float */
86 set_irn_pinned(call, op_pin_state_floats);
88 hook_func_call(current_ir_graph, call);
92 else if (get_irn_op(node) == op_Proj) {
94 * Remove memory and exception Proj's from
95 * const function calls.
97 call = get_Proj_pred(node);
98 if ((get_irn_op(call) != op_Call) ||
99 (get_irn_op(get_Call_mem(call)) != op_NoMem))
102 switch (get_Proj_proj(node)) {
103 case pn_Call_M_regular: {
104 ir_node *old_mem = get_irn_link(call);
106 exchange(node, old_mem);
108 case pn_Call_X_except:
109 case pn_Call_M_except:
110 exchange(node, new_Bad());
118 * optimize function calls by handling const functions
120 void optimize_funccalls(int force_run)
124 unsigned num_pure = 0;
126 if (! get_opt_real_func_call())
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);
137 if (get_irg_additional_properties(irg) & irg_const_function) {
138 /* already marked as a const function */
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);
148 /* Bad nodes usually do NOT produce anything, so it's ok */
152 if (op == op_Return) {
153 mem = get_Return_mem(node);
155 /* Bad nodes usually do NOT produce anything, so it's ok */
159 change = mem != get_irg_initial_mem(irg);
164 /* exception found */
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);
175 if (mode_M != get_irn_mode(mem))
178 change = mem != get_irg_initial_mem(irg);
185 /* no memory changes found, it's a const function */
186 set_irg_additional_property(irg, irg_const_function);
192 if (force_run || num_pure > 0) {
195 ctx.n_calls_removed_SymConst = 0;
196 ctx.n_calls_removed_Sel = 0;
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);
202 /* no need to do this on const functions */
203 if ((get_irg_additional_properties(irg) & irg_const_function) == 0) {
205 irg_walk_graph(irg, NULL, rem_mem_from_const_fkt_calls, &ctx);
208 /* changes were done */
209 set_irg_outs_inconsistent(irg);
210 set_irg_loopinfo_state(current_ir_graph, loopinfo_cf_inconsistent);
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);
222 if (get_firm_verbosity()) {
223 printf("No graphs without side effects detected\n");
229 * Walker: Walks over all graphs and evaluates calls with
230 * constant arguments.
231 * Currently used only for non-virtual calls.
233 static void eval_calls(ir_node *call, void *env)
235 ir_node *ptr, *param;
240 if (get_irn_op(call) != op_Call)
243 ptr = get_Call_ptr(call);
245 if (get_irn_op(ptr) != op_SymConst)
248 if (get_SymConst_kind(ptr) != symconst_addr_ent)
251 ent = get_SymConst_entity(ptr);
252 irg = get_entity_irg(ent);
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);
261 if (is_irn_constlike(param)) {
262 /* Found one: add to statistics */
264 ir_printf("%+F called with const %+F at position %d\n", ent, param, i);