X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fir%2Firgopt.c;h=15cb664d925ffae889c529f46e2f04716615e3fc;hb=8d2c83137a6273f1480ea9f633837e84db8a1939;hp=6bf712b11e808e980da1518728054e3fc53ad05f;hpb=1d265ff57b0137d181368d97cdbd93f3c14d94aa;p=libfirm diff --git a/ir/ir/irgopt.c b/ir/ir/irgopt.c index 6bf712b11..15cb664d9 100644 --- a/ir/ir/irgopt.c +++ b/ir/ir/irgopt.c @@ -1,18 +1,22 @@ -/* Coyright (C) 1998 - 2002 by Universitaet Karlsruhe -* All rights reserved. -* -* Author: Christian Schaefer, Goetz Lindenmaier, Sebastian Felis -* -* Optimizations for a whole ir graph, i.e., a procedure. -*/ +/* + * Project: libFIRM + * File name: ir/ir/irgopt.c + * Purpose: Optimizations for a whole ir graph, i.e., a procedure. + * Author: Christian Schaefer, Goetz Lindenmaier + * Modified by: Sebastian Felis + * Created: + * CVS-ID: $Id$ + * Copyright: (c) 1998-2003 Universität Karlsruhe + * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE. + */ -/* $Id$ */ #ifdef HAVE_CONFIG_H # include #endif # include +# include # include "irprog.h" # include "irgopt.h" @@ -21,10 +25,10 @@ # include "iropt_t.h" # include "irgwalk.h" # include "ircons.h" -# include "misc.h" # include "irgmod.h" # include "array.h" # include "pset.h" +# include "eset.h" # include "pdeq.h" /* Fuer code placement */ # include "irouts.h" # include "irloop.h" @@ -43,13 +47,18 @@ static void init_link (ir_node *n, void *env) { set_irn_link(n, NULL); } +#if 0 /* Old version. Avoids Ids. + This is not necessary: we do a postwalk, and get_irn_n + removes ids anyways. So it's much cheaper to call the + optimization less often and use the exchange() algorithm. */ static void optimize_in_place_wrapper (ir_node *n, void *env) { - int i; + int i, irn_arity; ir_node *optimized, *old; - for (i = 0; i < get_irn_arity(n); i++) { - /* get?irn_n skips Id nodes, so comparison old != optimized does not + irn_arity = get_irn_arity(n); + for (i = 0; i < irn_arity; i++) { + /* get_irn_n skips Id nodes, so comparison old != optimized does not show all optimizations. Therefore always set new predecessor. */ old = get_irn_n(n, i); optimized = optimize_in_place_2(old); @@ -61,6 +70,15 @@ optimize_in_place_wrapper (ir_node *n, void *env) { if (optimized != n) exchange (n, optimized); } } +#else +static void +optimize_in_place_wrapper (ir_node *n, void *env) { + ir_node *optimized = optimize_in_place_2(n); + if (optimized != n) exchange (n, optimized); +} +#endif + + void local_optimize_graph (ir_graph *irg) { @@ -113,7 +131,7 @@ get_new_node (ir_node * n) in a Block. */ static INLINE int compute_new_arity(ir_node *b) { - int i, res; + int i, res, irn_arity; int irg_v, block_v; irg_v = get_irg_block_visited(current_ir_graph); @@ -124,8 +142,8 @@ compute_new_arity(ir_node *b) { return block_v - irg_v; } else { /* compute the number of good predecessors */ - res = get_irn_arity(b); - for (i = 0; i < get_irn_arity(b); i++) + res = irn_arity = get_irn_arity(b); + for (i = 0; i < irn_arity; i++) if (get_irn_opcode(get_irn_n(b, i)) == iro_Bad) res--; /* save it in the flag. */ set_Block_block_visited(b, irg_v + res); @@ -160,6 +178,11 @@ copy_node (ir_node *n, void *env) { ir_node *nn, *block; int new_arity; + /* The end node looses it's flexible in array. This doesn't matter, + as dead node elimination builds End by hand, inlineing doesn't use + the End node. */ + //assert(n->op == op_End || ((_ARR_DESCR(n->in))->cookie != ARR_F_MAGIC)); + if (get_irn_opcode(n) == iro_Block) { block = NULL; new_arity = compute_new_arity(n); @@ -196,7 +219,7 @@ copy_node (ir_node *n, void *env) { static void copy_preds (ir_node *n, void *env) { ir_node *nn, *block; - int i, j; + int i, j, irn_arity; nn = get_new_node(n); @@ -207,7 +230,8 @@ copy_preds (ir_node *n, void *env) { if (get_irn_opcode(n) == iro_Block) { /* Don't copy Bad nodes. */ j = 0; - for (i = 0; i < get_irn_arity(n); i++) + irn_arity = get_irn_arity(n); + for (i = 0; i < irn_arity; i++) if (get_irn_opcode(get_irn_n(n, i)) != iro_Bad) { set_irn_n (nn, j, get_new_node(get_irn_n(n, i))); /*if (is_backedge(n, i)) set_backedge(nn, j);*/ @@ -231,7 +255,8 @@ copy_preds (ir_node *n, void *env) { block = get_nodes_Block(n); set_irn_n (nn, -1, get_new_node(block)); j = 0; - for (i = 0; i < get_irn_arity(n); i++) + irn_arity = get_irn_arity(n); + for (i = 0; i < irn_arity; i++) if (get_irn_opcode(get_irn_n(block, i)) != iro_Bad) { set_irn_n (nn, j, get_new_node(get_irn_n(n, i))); /*if (is_backedge(n, i)) set_backedge(nn, j);*/ @@ -245,7 +270,8 @@ copy_preds (ir_node *n, void *env) { if (get_irn_arity(n) == 1) exchange(n, get_irn_n(n, 0)); } else { - for (i = -1; i < get_irn_arity(n); i++) + irn_arity = get_irn_arity(n); + for (i = -1; i < irn_arity; i++) set_irn_n (nn, i, get_new_node(get_irn_n(n, i))); } /* Now the new node is complete. We can add it to the hash table for cse. @@ -259,7 +285,7 @@ static void copy_graph (void) { ir_node *oe, *ne; /* old end, new end */ ir_node *ka; /* keep alive */ - int i; + int i, irn_arity; oe = get_irg_end(current_ir_graph); /* copy the end node by hand, allocate dynamic in array! */ @@ -282,7 +308,8 @@ copy_graph (void) { /** ... and now the keep alives. **/ /* First pick the not marked block nodes and walk them. We must pick these first as else we will oversee blocks reachable from Phis. */ - for (i = 0; i < get_irn_arity(oe); i++) { + irn_arity = get_irn_arity(oe); + for (i = 0; i < irn_arity; i++) { ka = get_irn_n(oe, i); if ((get_irn_op(ka) == op_Block) && (get_irn_visited(ka) < get_irg_visited(current_ir_graph))) { @@ -294,7 +321,8 @@ copy_graph (void) { } /* Now pick the Phis. Here we will keep all! */ - for (i = 0; i < get_irn_arity(oe); i++) { + irn_arity = get_irn_arity(oe); + for (i = 0; i < irn_arity; i++) { ka = get_irn_n(oe, i); if ((get_irn_op(ka) == op_Phi)) { if (get_irn_visited(ka) < get_irg_visited(current_ir_graph)) { @@ -356,11 +384,13 @@ copy_graph_env (void) { copy_preds(get_irg_bad(current_ir_graph), NULL); } set_irg_bad(current_ir_graph, get_new_node(get_irg_bad(current_ir_graph))); + /* GL removed: we need unknown with mode for analyses. if (get_irn_link(get_irg_unknown(current_ir_graph)) == NULL) { copy_node(get_irg_unknown(current_ir_graph), NULL); copy_preds(get_irg_unknown(current_ir_graph), NULL); } set_irg_unknown(current_ir_graph, get_new_node(get_irg_unknown(current_ir_graph))); + */ } /* Copies all reachable nodes to a new obstack. Removes bad inputs @@ -507,10 +537,13 @@ void remove_bad_predecessors(ir_graph *irg) { /* Funcionality for inlining */ /**********************************************************************/ -/* Copy node for inlineing. Copies the node by calling copy_node and - then updates the entity if it's a local one. env must be a pointer - to the frame type of the procedure. The new entities must be in - the link field of the entities. */ +/* Copy node for inlineing. Updates attributes that change when + * inlineing but not for dead node elimination. + * + * Copies the node by calling copy_node and then updates the entity if + * it's a local one. env must be a pointer of the frame type of the + * inlined procedure. The new entities must be in the link field of + * the entities. */ static INLINE void copy_node_inline (ir_node *n, void *env) { ir_node *new; @@ -523,9 +556,13 @@ copy_node_inline (ir_node *n, void *env) { if (get_entity_owner(get_Sel_entity(n)) == frame_tp) { set_Sel_entity(new, get_entity_link(get_Sel_entity(n))); } + } else if (get_irn_op(n) == op_Block) { + new = get_new_node (n); + new->attr.block.irg = current_ir_graph; } } + void inline_method(ir_node *call, ir_graph *called_graph) { ir_node *pre_call; ir_node *post_call, *post_bl; @@ -535,7 +572,7 @@ void inline_method(ir_node *call, ir_graph *called_graph) { ir_node **cf_pred; ir_node *ret, *phi; ir_node *cf_op = NULL, *bl; - int arity, n_ret, n_exc, n_res, i, j, rem_opt; + int arity, n_ret, n_exc, n_res, i, j, rem_opt, irn_arity; type *called_frame; if (!get_optimize() || !get_opt_inline()) return; @@ -656,10 +693,12 @@ void inline_method(ir_node *call, ir_graph *called_graph) { set_irg_current_block(current_ir_graph, post_bl); /* just to make sure */ /* -- archive keepalives -- */ - for (i = 0; i < get_irn_arity(end); i++) + irn_arity = get_irn_arity(end); + for (i = 0; i < irn_arity; i++) add_End_keepalive(get_irg_end(current_ir_graph), get_irn_n(end, i)); - /* The new end node will die, but the in array is not on the obstack ... */ - free_End(end); + + /* The new end node will die. We need not free as the in array is on the obstack: + copy_node only generated 'D' arrays. */ /* -- Return nodes by Jump nodes. -- */ @@ -758,38 +797,45 @@ void inline_method(ir_node *call, ir_graph *called_graph) { free(res_pred); free(cf_pred); -/* -- - If the exception control flow from the Call directly branched to the - end block we now have the following control flow predecessor pattern: - ProjX -> Tuple -> Jmp. - We must remove the Jmp along with it's empty block and add Jmp's - predecessors as predecessors of this end block. -- */ - /* find the problematic predecessor of the end block. */ - end_bl = get_irg_end_block(current_ir_graph); - for (i = 0; i < get_Block_n_cfgpreds(end_bl); i++) { - cf_op = get_Block_cfgpred(end_bl, i); - if (get_irn_op(cf_op) == op_Proj) { - cf_op = get_Proj_pred(cf_op); - if (get_irn_op(cf_op) == op_Tuple) { - cf_op = get_Tuple_pred(cf_op, 1); - assert(get_irn_op(cf_op) == op_Jmp); - break; + if (n_exc > 0) { + /* -- If the exception control flow from the inlined Call directly + branched to the end block we now have the following control + flow predecessor pattern: ProjX -> Tuple -> Jmp. We must + remove the Jmp along with it's empty block and add Jmp's + predecessors as predecessors of this end block. No problem if + there is no exception, because then branches Bad to End which + is fine. -- */ + /* find the problematic predecessor of the end block. */ + end_bl = get_irg_end_block(current_ir_graph); + for (i = 0; i < get_Block_n_cfgpreds(end_bl); i++) { + cf_op = get_Block_cfgpred(end_bl, i); + if (get_irn_op(cf_op) == op_Proj) { + cf_op = get_Proj_pred(cf_op); + if ((get_irn_op(cf_op) == op_Tuple) && (cf_op == call)) { + // There are unoptimized tuples from inlineing before when no exc + assert(get_Proj_proj(get_Block_cfgpred(end_bl, i)) == pn_Call_X_except); + cf_op = get_Tuple_pred(cf_op, pn_Call_X_except); + assert(get_irn_op(cf_op) == op_Jmp); + break; + } } } - } - /* repair */ - if (i < get_Block_n_cfgpreds(end_bl)) { - bl = get_nodes_Block(cf_op); - arity = get_Block_n_cfgpreds(end_bl) + get_Block_n_cfgpreds(bl) - 1; - cf_pred = (ir_node **) malloc (arity * sizeof (ir_node *)); - for (j = 0; j < i; j++) - cf_pred[j] = get_Block_cfgpred(end_bl, j); - for (j = j; j < i + get_Block_n_cfgpreds(bl); j++) - cf_pred[j] = get_Block_cfgpred(bl, j-i); - for (j = j; j < arity; j++) - cf_pred[j] = get_Block_cfgpred(end_bl, j-get_Block_n_cfgpreds(bl) +1); - set_irn_in(end_bl, arity, cf_pred); - free(cf_pred); + /* repair */ + if (i < get_Block_n_cfgpreds(end_bl)) { + bl = get_nodes_Block(cf_op); + arity = get_Block_n_cfgpreds(end_bl) + get_Block_n_cfgpreds(bl) - 1; + cf_pred = (ir_node **) malloc (arity * sizeof (ir_node *)); + for (j = 0; j < i; j++) + cf_pred[j] = get_Block_cfgpred(end_bl, j); + for (j = j; j < i + get_Block_n_cfgpreds(bl); j++) + cf_pred[j] = get_Block_cfgpred(bl, j-i); + for (j = j; j < arity; j++) + cf_pred[j] = get_Block_cfgpred(end_bl, j-get_Block_n_cfgpreds(bl) +1); + set_irn_in(end_bl, arity, cf_pred); + free(cf_pred); + // Remove the exception pred from post-call Tuple. + set_Tuple_pred(call, pn_Call_X_except, new_Bad()); + } } /* -- Turn cse back on. -- */ @@ -806,14 +852,34 @@ static int pos; I didn't get a version with NEW_ARR_F to run. */ #define MAX_INLINE 1024 +/* given an Call node, returns the irg called. NULL if not + * known. */ +static ir_graph *get_call_called_irg(ir_node *call) { + ir_node *addr; + tarval *tv; + ir_graph *called_irg = NULL; + + assert(get_irn_op(call) == op_Call); + + addr = get_Call_ptr(call); + if (get_irn_op(addr) == op_Const) { + /* Check whether the constant is the pointer to a compiled entity. */ + tv = get_Const_tarval(addr); + if (tarval_to_entity(tv)) + called_irg = get_entity_irg(tarval_to_entity(tv)); + } + return called_irg; +} + static void collect_calls(ir_node *call, void *env) { + + if (get_irn_op(call) != op_Call) return; + ir_node **calls = (ir_node **)env; ir_node *addr; tarval *tv; ir_graph *called_irg; - if (get_irn_op(call) != op_Call) return; - addr = get_Call_ptr(call); if (get_irn_op(addr) == op_Const) { /* Check whether the constant is the pointer to a compiled entity. */ @@ -871,6 +937,194 @@ void inline_small_irgs(ir_graph *irg, int size) { current_ir_graph = rem; } +typedef struct { + int n_nodes; /* Nodes in graph except Id, Tuple, Proj, Start, End */ + int n_nodes_orig; /* for statistics */ + eset *call_nodes; /* All call nodes in this graph */ + int n_call_nodes; + int n_call_nodes_orig; /* for statistics */ + int n_callers; /* Number of known graphs that call this graphs. */ + int n_callers_orig; /* for statistics */ +} inline_irg_env; + +static inline_irg_env *new_inline_irg_env(void) { + inline_irg_env *env = malloc(sizeof(inline_irg_env)); + env->n_nodes = -2; /* uncount Start, End */ + env->n_nodes_orig = -2; /* uncount Start, End */ + env->call_nodes = eset_create(); + env->n_call_nodes = 0; + env->n_call_nodes_orig = 0; + env->n_callers = 0; + env->n_callers_orig = 0; + return env; +} + +static void free_inline_irg_env(inline_irg_env *env) { + eset_destroy(env->call_nodes); + free(env); +} + +static void collect_calls2(ir_node *call, void *env) { + inline_irg_env *x = (inline_irg_env *)env; + ir_op *op = get_irn_op(call); + + /* count nodes in irg */ + if (op != op_Proj && op != op_Tuple && op != op_Sync) { + x->n_nodes++; + x->n_nodes_orig++; + } + + if (op != op_Call) return; + + /* collect all call nodes */ + eset_insert(x->call_nodes, (void *)call); + x->n_call_nodes++; + x->n_call_nodes_orig++; + + /* count all static callers */ + ir_graph *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_optimize() && get_opt_inline())) return; + + /* extend all irgs by a temporary datastructure for inlineing. */ + for (i = 0; i < n_irgs; ++i) + set_irg_link(get_irp_irg(i), new_inline_irg_env()); + + /* Precompute information in temporary datastructure. */ + for (i = 0; i < n_irgs; ++i) { + current_ir_graph = get_irp_irg(i); + assert(get_irg_phase_state(current_ir_graph) != phase_building); + + 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)) { + ir_graph *callee = get_call_called_irg(call); + if (env->n_nodes > maxsize) break; + if (callee && is_leave(callee) && is_smaller(callee, leavesize)) { + if (!phiproj_computed) { + phiproj_computed = 1; + collect_phiprojs(current_ir_graph); + } + inline_irg_env *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)) { + 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); + } + inline_irg_env *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. Pinns all floating nodes to a block where they */ @@ -884,7 +1138,7 @@ static pdeq *worklist; /* worklist of ir_node*s */ static void place_floats_early (ir_node *n) { - int i, start; + int i, start, irn_arity; /* we must not run into an infinite loop */ assert (irn_not_visited(n)); @@ -899,14 +1153,16 @@ place_floats_early (ir_node *n) if ((get_irn_op(n) == op_Const) || (get_irn_op(n) == op_SymConst) || - (is_Bad(n))) { + (is_Bad(n)) || + (get_irn_op(n) == op_Unknown)) { /* These nodes will not be placed by the loop below. */ b = get_irg_start_block(current_ir_graph); depth = 1; } /* find the block for this node. */ - for (i = 0; i < get_irn_arity(n); i++) { + irn_arity = get_irn_arity(n); + for (i = 0; i < irn_arity; i++) { ir_node *dep = get_irn_n(n, i); ir_node *dep_block; if ((irn_not_visited(dep)) && @@ -934,7 +1190,8 @@ place_floats_early (ir_node *n) /* Add predecessors of non floating nodes on worklist. */ start = (get_irn_op(n) == op_Block) ? 0 : -1; - for (i = start; i < get_irn_arity(n); i++) { + irn_arity = get_irn_arity(n); + for (i = start; i < irn_arity; i++) { ir_node *pred = get_irn_n(n, i); if (irn_not_visited(pred)) { pdeq_putr (worklist, pred); @@ -975,9 +1232,10 @@ consumer_dom_dca (ir_node *dca, ir_node *consumer, ir_node *producer) if (get_irn_op(consumer) == op_Phi) { /* our comsumer is a Phi-node, the effective use is in all those blocks through which the Phi-node reaches producer */ - int i; + int i, irn_arity; ir_node *phi_block = get_nodes_Block(consumer); - for (i = 0; i < get_irn_arity(consumer); i++) { + irn_arity = get_irn_arity(consumer); + for (i = 0; i < irn_arity; i++) { if (get_irn_n(consumer, i) == producer) { block = get_nodes_Block(get_Block_cfgpred(phi_block, i)); } @@ -1173,7 +1431,9 @@ static void merge_blocks(ir_node *n, void *env) { while (irn_not_visited(b) && (!is_Bad(new)) && (new != b)) { /* We would have to run gigo if new is bad, so we promote it directly below. */ - assert(((b == new) || get_opt_control_flow_straightening() || get_opt_control_flow_weak_simplification()) && + assert(((b == new) || + get_opt_control_flow_straightening() || + get_opt_control_flow_weak_simplification()) && ("strange flag setting")); exchange (b, new); b = new; @@ -1482,12 +1742,17 @@ static void walk_critical_cf_edges(ir_node *n, void *env) { (get_irn_arity(n) > 1)) { arity = get_irn_arity(n); + if (n == get_irg_end_block(current_ir_graph)) + return; // No use to add a block here. + for (i=0; iobst, 1); /* set predecessor of new block */ in[0] = pre;