From: Matthias Braun Date: Tue, 5 Sep 2006 16:47:48 +0000 (+0000) Subject: alternative algo for computing extbbs X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=f6cc87ea620e16ecb9d388f54abc8e76906e5488;p=libfirm alternative algo for computing extbbs [r8173] --- diff --git a/ir/ana/irextbb2.c b/ir/ana/irextbb2.c new file mode 100644 index 000000000..6826e615b --- /dev/null +++ b/ir/ana/irextbb2.c @@ -0,0 +1,225 @@ +/* + * Project: libFIRM + * File name: ir/ana/irextbb2.c + * Purpose: Alternate extended basic block computation + * Author: Matthias Braun + * Modified by: + * Created: 5.2005 + * CVS-ID: $Id$ + * Copyright: (c) 2002-2005 Universität Karlsruhe + * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE. + */ + +/** + * @file irextbb.c + * + * Alternative algorithm for computing extended basic blocks (using out edges + * and execution frequencies) + * + * @author Matthias Braun + */ +#include "irextbb_t.h" +#include "irgwalk.h" +#include "irnode_t.h" +#include "irgraph_t.h" +#include "iredges_t.h" +#include "irouts.h" +#include "xmalloc.h" +#include "irprintf.h" +#include "execfreq.h" + +typedef struct _env { + struct obstack *obst; /**< the obstack where allocations took place */ + ir_extblk *head; /**< head of the list of all extended blocks */ + exec_freq_t *execfreqs; +} env_t; + +/** + * allocate a new extended block header. + */ +static ir_extblk *allocate_extblk(ir_node *block, env_t *env) +{ + ir_extblk *extblk = obstack_alloc(env->obst, sizeof(*extblk)); + + extblk->kind = k_ir_extblk; + extblk->visited = 1; + extblk->blks = (ir_node **)env->head; + extblk->link = block; + env->head = extblk; + + set_Block_extbb(block, extblk); + set_irn_link(block, NULL); + + return extblk; +} + +/** + * add a block to an extended block + */ +static void addto_extblk(ir_extblk *extblk, ir_node *block) +{ + /* link all blocks belonging to this extended block */ + set_irn_link(block, extblk->link); + + extblk->link = block; + extblk->visited++; + + set_Block_extbb(block, extblk); +} + +/** + * Returns the number of block successors. + * we are interested only in 1, 2 and >2. + */ +static int get_block_n_succs(ir_node *block) { + if (edges_activated(current_ir_graph)) { + const ir_edge_t *edge; + + edge = get_block_succ_first(block); + if (! edge) + return 0; + edge = get_block_succ_next(block, edge); + if (! edge) + return 1; + edge = get_block_succ_next(block, edge); + return edge ? 3 : 2; + } + + return get_Block_n_cfg_outs(block); +} + +static void pick_successor(ir_node *block, ir_extblk *extblk, env_t *env); + +static void create_extblk(ir_node *block, env_t *env) +{ + if(irn_visited(block)) + return; + + ir_extblk *extblk = allocate_extblk(block, env); + mark_irn_visited(block); + + pick_successor(block, extblk, env); +} + +static void pick_successor(ir_node *block, ir_extblk *extblk, env_t *env) +{ + const ir_edge_t *edge; + ir_node *best_succ = NULL; + double best_execfreq = -1; + + /* More than two successors means we have a jump table. + * we cannot include a jump target into the current extended + * basic block, so create a new one here. + */ + if(get_block_n_succs(block) > 2) { + const ir_edge_t *edge; + + foreach_block_succ(block, edge) { + ir_node *succ = get_edge_src_irn(edge); + create_extblk(succ, env); + } + + return; + } + + foreach_block_succ(block, edge) { + ir_node *succ = get_edge_src_irn(edge); + double execfreq; + + if(get_Block_n_cfgpreds(succ) > 1) { + create_extblk(succ, env); + continue; + } + + execfreq = get_block_execfreq(env->execfreqs, succ); + + // remember best sucessor and make non best successor with only 1 + // pred block to new extbb leaders + if(execfreq > best_execfreq) { + if(best_succ != NULL) { + create_extblk(best_succ, env); + } + + best_execfreq = execfreq; + best_succ = succ; + } else { + create_extblk(succ, env); + } + } + + // add best successor and recursively try to pick more + if(best_succ != NULL) { + addto_extblk(extblk, best_succ); + mark_irn_visited(best_succ); + pick_successor(best_succ, extblk, env); + } +} + +/* + * Compute the extended basic blocks for a graph + */ +void compute_extbb_execfreqs(ir_graph *irg, exec_freq_t *execfreqs) { + env_t env; + ir_extblk *extbb, *next; + ir_node *endblock; + + if (irg->extbb_obst) { + obstack_free(irg->extbb_obst, NULL); + } else { + irg->extbb_obst = xmalloc(sizeof(*irg->extbb_obst)); + } + obstack_init(irg->extbb_obst); + + env.obst = irg->extbb_obst; + env.head = NULL; + env.execfreqs = execfreqs; + + assure_irg_outs(irg); + + /* we must mark nodes, so increase the visited flag */ + inc_irg_visited(irg); + create_extblk(get_irg_start_block(irg), &env); + + // the end block needs a extbb assigned (even for endless loops) + endblock = get_irg_end_block(irg); + if(!irn_visited(endblock)) { + create_extblk(endblock, &env); + } + + /* + * Ok, we have now the list of all extended blocks starting with env.head + * every extended block "knowns" the number of blocks in visited and + * the blocks are linked in link. + * Now we can create arrays that hold the blocks, some kind of "out" edges + * for the extended block + */ + for (extbb = env.head; extbb; extbb = next) { + int i, len = (int)extbb->visited; + ir_node *block; + + next = (ir_extblk *)extbb->blks; + + extbb->blks = NEW_ARR_D(ir_node *, env.obst, len); + + for (block = extbb->link, i = 0; i < len; ++i) { + ir_node *nblock = get_irn_link(block); + + /* ensure that the leader is the first one */ + extbb->blks[len - 1 - i] = block; + set_irn_link(block, NULL); + block = nblock; + } + + for(i = 0; i < len; ++i) { + if(i > 0) + printf(", "); + ir_printf("%+F", extbb->blks[i]); + } + printf("\n"); + + extbb->link = NULL; + extbb->visited = 0; + } + + irg->extblk_state = extblk_valid; +}