* Project: libFIRM
* File name: ir/opt/ldstopt.c
* Purpose: optimization of function calls
- * Author:
+ * Author: Michael M. Beck
* Created:
* CVS-ID: $Id$
* Copyright: (c) 1998-2004 Universität Karlsruhe
typedef struct _env_t {
eset *pure_fkt; /**< set containing all real functions */
int changed; /**< flag, is set if a graph was changed */
+ int n_calls_removed_SymConst;
+ int n_calls_removed_Sel;
} env_t;
/**
ir_node *call, *ptr, *mem;
entity *ent;
- if (get_irn_op(node) != op_Proj || get_irn_mode(node) != mode_M)
- return;
-
- /* look at Memory Proj's */
- call = get_Proj_pred(node);
- if (get_irn_op(call) != op_Call)
- return;
-
- ptr = get_Call_ptr(call);
- if (get_irn_op(ptr) != op_SymConst || get_SymConst_kind(ptr) != symconst_addr_ent)
- return;
-
- ent = get_SymConst_entity(ptr);
-
- if (! eset_contains(ctx->pure_fkt, ent))
- return;
-
- /* ok, if we get here we found a call to a pure function,
- * route the NoMem node to the call */
- mem = get_Call_mem(call);
+ if (get_irn_op(node) == op_Call) {
+ call = node;
- exchange(node, mem);
- set_Call_mem(call, new_r_NoMem(current_ir_graph));
+ set_irn_link(call, NULL);
- /* finally, this call can floats */
- set_irn_pinned(call, op_pin_state_floats);
+ ptr = get_Call_ptr(call);
+ if (get_irn_op(ptr) == op_SymConst && get_SymConst_kind(ptr) == symconst_addr_ent) {
- hook_func_call(current_ir_graph, call);
+ ent = get_SymConst_entity(ptr);
- ctx->changed = 1;
+ if (! eset_contains(ctx->pure_fkt, ent))
+ return;
+ ctx->n_calls_removed_SymConst++;
+ }
+ else if (get_irn_op(ptr) == op_Sel &&
+ get_irg_callee_info_state(current_ir_graph) == irg_callee_info_consistent) {
+ /* If all possible callees are real functions, we can remove the memory edge. */
+ int i, n_callees = get_Call_n_callees(call);
+ if (n_callees == 0)
+ /* This is kind of strange: dying code or a Call that will raise an exception
+ when executed as there is no implementation to call. So better not
+ optimize. */
+ return;
+ for (i = 0; i < n_callees; ++i) {
+ if (! eset_contains(ctx->pure_fkt, get_Call_callee(call, i)))
+ return;
+ }
+ ctx->n_calls_removed_Sel++;
+ }
+ else return;
+
+ /* ok, if we get here we found a call to a pure function,
+ * route the NoMem node to the call */
+ mem = get_Call_mem(call);
+
+ set_irn_link(call, mem);
+ set_Call_mem(call, new_r_NoMem(current_ir_graph));
+
+ /* finally, this call can float */
+ set_irn_pinned(call, op_pin_state_floats);
+
+ hook_func_call(current_ir_graph, call);
+
+ ctx->changed = 1;
+ } else if (get_irn_op(node) == op_Proj) {
+ call = get_Proj_pred(node);
+ if ((get_irn_op(call) != op_Call) ||
+ (get_irn_op(get_Call_mem(call)) != op_NoMem))
+ return;
+
+ switch(get_Proj_proj(node)) {
+ case pn_Call_M_regular: {
+ ir_node *old_mem = get_irn_link(call);
+ if (old_mem) exchange(node, old_mem);
+ } break;
+ case pn_Call_X_except:
+ case pn_Call_M_except:
+ exchange(node, new_Bad());
+ break;
+ default: ;
+ }
+ }
}
/*
if (! get_opt_real_func_call())
return;
- /* first step: detect, which functions are pure, ie do NOT change any memory */
+ /* first step: detect, which functions are pure, i.e. do NOT change any memory */
for (i = 0, n = get_irp_n_irgs(); i < n; ++i) {
ir_graph *irg = get_irp_irg(i);
ir_node *end = get_irg_end(irg);
/* visit every Return */
for (j = 0, k = get_Block_n_cfgpreds(endbl); j < k; ++j) {
- ir_node *ret = get_Block_cfgpred(endbl, j);
+ ir_node *node = get_Block_cfgpred(endbl, j);
+ ir_op *op = get_irn_op(node);
ir_node *mem;
/* Bad nodes usually do NOT produce anything, so it's ok */
- if (is_Bad(ret))
+ if (op == op_Bad)
continue;
- mem = get_Return_mem(ret);
+ if (op == op_Return) {
+ mem = get_Return_mem(node);
- /* Bad nodes usually do NOT produce anything, so it's ok */
- if (is_Bad(mem))
- continue;
+ /* Bad nodes usually do NOT produce anything, so it's ok */
+ if (is_Bad(mem))
+ continue;
- change = mem != get_irg_initial_mem(irg);
- if (change)
+ change = mem != get_irg_initial_mem(irg);
+ if (change)
+ break;
+ }
+ else {
+ /* exception found */
+ change = 1;
break;
+ }
}
if (! change) {
if (num_pure > 0) {
env_t ctx;
+ entity *ent;
ctx.pure_fkt = pure_fkt;
+ ctx.n_calls_removed_SymConst = 0;
+ ctx.n_calls_removed_Sel = 0;
/* all calls of pure functions can be transformed into FuncCalls */
for (i = 0, n = get_irp_n_irgs(); i < n; ++i) {
set_irg_loopinfo_state(current_ir_graph, loopinfo_cf_inconsistent);
}
}
+
+ if (get_firm_verbosity()) {
+ printf("Detected %d functions without side effects.\n", num_pure);
+ printf("Optimizes %d(SymConst) + %d(Sel) calls to these functions.\n",
+ ctx.n_calls_removed_SymConst, ctx.n_calls_removed_Sel);
+ if (get_firm_verbosity() > 1) {
+ for (ent = eset_first(pure_fkt); ent; ent = eset_next(pure_fkt)) {
+ printf(" "); DDMEO(ent);
+ }
+ }
+ }
+
+ } else {
+ if (get_firm_verbosity()) {
+ printf("No functions without side effects detected\n");
+ }
}
eset_destroy(pure_fkt);