+ /* collect all call nodes */
+ eset_insert(x->call_nodes, (void *)call);
+ x->n_call_nodes++;
+ x->n_call_nodes_orig++;
+
+ /* count all static callers */
+ callee = get_call_called_irg(call);
+ if (callee) {
+ ((inline_irg_env *)get_irg_link(callee))->n_callers++;
+ ((inline_irg_env *)get_irg_link(callee))->n_callers_orig++;
+ }
+}
+
+INLINE static int is_leave(ir_graph *irg) {
+ return (((inline_irg_env *)get_irg_link(irg))->n_call_nodes == 0);
+}
+
+INLINE static int is_smaller(ir_graph *callee, int size) {
+ return (((inline_irg_env *)get_irg_link(callee))->n_nodes < size);
+}
+
+
+/**
+ * Inlines small leave methods at call sites where the called address comes
+ * from a Const node that references the entity representing the called
+ * method.
+ * The size argument is a rough measure for the code size of the method:
+ * Methods where the obstack containing the firm graph is smaller than
+ * size are inlined.
+ */
+void inline_leave_functions(int maxsize, int leavesize, int size) {
+ inline_irg_env *env;
+ int i, n_irgs = get_irp_n_irgs();
+ ir_graph *rem = current_ir_graph;
+ int did_inline = 1;
+
+ if (!(get_opt_optimize() && get_opt_inline())) return;
+
+ /* extend all irgs by a temporary data structure for inlineing. */
+ for (i = 0; i < n_irgs; ++i)
+ set_irg_link(get_irp_irg(i), new_inline_irg_env());
+
+ /* Precompute information in temporary data structure. */
+ for (i = 0; i < n_irgs; ++i) {
+ current_ir_graph = get_irp_irg(i);
+ assert(get_irg_phase_state(current_ir_graph) != phase_building);
+ assert(get_irg_callee_info_state(current_ir_graph) == irg_callee_info_none);
+
+ irg_walk(get_irg_end(current_ir_graph), NULL, collect_calls2,
+ get_irg_link(current_ir_graph));
+ env = (inline_irg_env *)get_irg_link(current_ir_graph);
+ }
+
+ /* and now inline.
+ Inline leaves recursively -- we might construct new leaves. */
+ //int itercnt = 1;
+ while (did_inline) {
+ //printf("iteration %d\n", itercnt++);
+ did_inline = 0;
+ for (i = 0; i < n_irgs; ++i) {
+ ir_node *call;
+ eset *walkset;
+ int phiproj_computed = 0;
+
+ current_ir_graph = get_irp_irg(i);
+ env = (inline_irg_env *)get_irg_link(current_ir_graph);
+
+ /* we can not walk and change a set, nor remove from it.
+ So recompute.*/
+ walkset = env->call_nodes;
+ env->call_nodes = eset_create();
+ for (call = eset_first(walkset); call; call = eset_next(walkset)) {
+ inline_irg_env *callee_env;
+ ir_graph *callee = get_call_called_irg(call);
+
+ if (env->n_nodes > maxsize) break;
+ if (callee &&
+ ((is_leave(callee) && is_smaller(callee, leavesize)) ||
+ (get_irg_inline_property(callee) == irg_inline_forced))) {
+ if (!phiproj_computed) {
+ phiproj_computed = 1;
+ collect_phiprojs(current_ir_graph);
+ }
+ callee_env = (inline_irg_env *)get_irg_link(callee);
+// printf(" %s: Inlineing %s.\n", get_entity_name(get_irg_entity(current_ir_graph)),
+// get_entity_name(get_irg_entity(callee)));
+ inline_method(call, callee);
+ did_inline = 1;
+ env->n_call_nodes--;
+ eset_insert_all(env->call_nodes, callee_env->call_nodes);
+ env->n_call_nodes += callee_env->n_call_nodes;
+ env->n_nodes += callee_env->n_nodes;
+ callee_env->n_callers--;
+ } else {
+ eset_insert(env->call_nodes, call);
+ }
+ }
+ eset_destroy(walkset);
+ }
+ }
+
+ //printf("Non leaves\n");
+ /* inline other small functions. */
+ for (i = 0; i < n_irgs; ++i) {
+ ir_node *call;
+ eset *walkset;
+ int phiproj_computed = 0;
+
+ current_ir_graph = get_irp_irg(i);
+ env = (inline_irg_env *)get_irg_link(current_ir_graph);
+
+ /* we can not walk and change a set, nor remove from it.
+ So recompute.*/
+ walkset = env->call_nodes;
+ env->call_nodes = eset_create();
+ for (call = eset_first(walkset); call; call = eset_next(walkset)) {
+ inline_irg_env *callee_env;
+ ir_graph *callee = get_call_called_irg(call);
+
+ if (env->n_nodes > maxsize) break;
+ if (callee && is_smaller(callee, size)) {
+ if (!phiproj_computed) {
+ phiproj_computed = 1;
+ collect_phiprojs(current_ir_graph);
+ }
+ callee_env = (inline_irg_env *)get_irg_link(callee);
+// printf(" %s: Inlineing %s.\n", get_entity_name(get_irg_entity(current_ir_graph)),
+// get_entity_name(get_irg_entity(callee)));
+ inline_method(call, callee);
+ did_inline = 1;
+ env->n_call_nodes--;
+ eset_insert_all(env->call_nodes, callee_env->call_nodes);
+ env->n_call_nodes += callee_env->n_call_nodes;
+ env->n_nodes += callee_env->n_nodes;
+ callee_env->n_callers--;
+ } else {
+ eset_insert(env->call_nodes, call);
+ }
+ }
+ eset_destroy(walkset);
+ }
+
+ for (i = 0; i < n_irgs; ++i) {
+ current_ir_graph = get_irp_irg(i);
+#if 0
+ env = (inline_irg_env *)get_irg_link(current_ir_graph);
+ if ((env->n_call_nodes_orig != env->n_call_nodes) ||
+ (env->n_callers_orig != env->n_callers))
+ printf("Nodes:%3d ->%3d, calls:%3d ->%3d, callers:%3d ->%3d, -- %s\n",
+ env->n_nodes_orig, env->n_nodes, env->n_call_nodes_orig, env->n_call_nodes,
+ env->n_callers_orig, env->n_callers,
+ get_entity_name(get_irg_entity(current_ir_graph)));
+#endif
+ free_inline_irg_env((inline_irg_env *)get_irg_link(current_ir_graph));
+ }
+
+ current_ir_graph = rem;
+}
+
+/*-----------------------------------------------------------------*/
+/* Code Placement. Pins all floating nodes to a block where they */
+/* will be executed only if needed. */
+/*-----------------------------------------------------------------*/
+
+/**
+ * Find the earliest correct block for N. --- Place N into the
+ * same Block as its dominance-deepest Input.
+ */