X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fopt%2Fopt_blocks.c;h=a2a0452060f75ccefc4002b331fcb87642f6be07;hb=d5d7159c209a9e5c5fa276f770b5b28a217990a8;hp=61d898047258f3858bb37330e515bb1b4104a536;hpb=76c005588cd5c7c5f41e0b38f61c2ee54d9faa51;p=libfirm diff --git a/ir/opt/opt_blocks.c b/ir/opt/opt_blocks.c index 61d898047..a2a045206 100644 --- a/ir/opt/opt_blocks.c +++ b/ir/opt/opt_blocks.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved. + * Copyright (C) 1995-2011 University of Karlsruhe. All right reserved. * * This file is part of libFirm. * @@ -23,13 +23,13 @@ * @author Michael Beck * @version $Id$ * - * This phase find congruent blocks. Works currently for - * predecessors of the end block only. + * This phase find congruent blocks. * Two block are congruent, if they contains only equal calculations. */ #include "config.h" -#include "ircons.h" + #include "iroptimize.h" +#include "ircons.h" #include "irgmod.h" #include "irgraph_t.h" #include "irnode_t.h" @@ -38,7 +38,13 @@ #include "trouts.h" #include "irgwalk.h" #include "set.h" +#include "irpass.h" #include "debug.h" +#include "irtools.h" + +/* define this for general block shaping: congruent blocks + are found not only before the end block but anywhere in the graph */ +#define GENERAL_SHAPE typedef struct partition_t partition_t; typedef struct block_t block_t; @@ -48,15 +54,20 @@ typedef struct phi_t phi_t; typedef struct opcode_key_t opcode_key_t; typedef struct listmap_entry_t listmap_entry_t; typedef struct environment_t environment_t; +typedef struct pred_t pred_t; /** An opcode map key. */ struct opcode_key_t { - ir_opcode code; /**< The Firm opcode. */ + unsigned code; /**< The Firm opcode. */ ir_mode *mode; /**< The mode of all nodes in the partition. */ int arity; /**< The arity of this opcode (needed for Phi etc. */ union { - long proj; /**< For Proj nodes, its proj number */ - ir_entity *ent; /**< For Sel Nodes, its entity */ + long proj; /**< For Proj nodes, its proj number */ + ir_entity *ent; /**< For Sel nodes, its entity */ + ir_tarval *tv; /**< For Const nodes, its tarval */ + symconst_symbol sym; /**< For SymConst nodes, its symbol .*/ + void *addr; /**< Alias all addresses. */ + int intVal; /**< For Conv/Div nodes: strict/remainderless. */ } u; }; @@ -81,7 +92,8 @@ struct block_t { node_t *cf_root; /**< The control flow root node of this block. */ pair_t *input_pairs; /**< The list of inputs to this block. */ phi_t *phis; /**< The list of Phis in this block. */ - block_t *all_next; /**< links all craeted blocks. */ + block_t *all_next; /**< Links all created blocks. */ + int meet_input; /**< Input number of this block in the meet-block. */ }; /** A node. */ @@ -101,7 +113,7 @@ struct environment_t { struct obstack obst; /** obstack for temporary data */ }; -/** A node, input index pair. */ +/** A (node, input index) pair. */ struct pair_t { pair_t *next; /**< Points to the next pair entry. */ ir_node *irn; /**< The IR-node. */ @@ -116,6 +128,12 @@ struct phi_t { ir_node **ins; /**< A new in array once allocated. */ }; +/** Describes a predecessor input. */ +struct pred_t { + ir_node *pred; /**< The predecessor. */ + int index; /**< Its input index. */ +}; + /** * An entry in the list_map. */ @@ -143,7 +161,8 @@ DEBUG_ONLY(static unsigned part_nr = 0); /** * Dump partition to output. */ -static void dump_partition(const char *msg, const partition_t *part) { +static void dump_partition(const char *msg, const partition_t *part) +{ const block_t *block; int first = 1; @@ -158,7 +177,8 @@ static void dump_partition(const char *msg, const partition_t *part) { /** * Dumps a list. */ -static void dump_list(const char *msg, const block_t *block) { +static void dump_list(const char *msg, const block_t *block) +{ const block_t *p; int first = 1; @@ -177,9 +197,10 @@ static void dump_list(const char *msg, const block_t *block) { /** * Compare two pointer values of a listmap. */ -static int listmap_cmp_ptr(const void *elt, const void *key, size_t size) { - const listmap_entry_t *e1 = elt; - const listmap_entry_t *e2 = key; +static int listmap_cmp_ptr(const void *elt, const void *key, size_t size) +{ + const listmap_entry_t *e1 = (const listmap_entry_t*)elt; + const listmap_entry_t *e2 = (const listmap_entry_t*)key; (void) size; return e1->id != e2->id; @@ -190,7 +211,8 @@ static int listmap_cmp_ptr(const void *elt, const void *key, size_t size) { * * @param map the listmap */ -static void listmap_init(listmap_t *map) { +static void listmap_init(listmap_t *map) +{ map->map = new_set(listmap_cmp_ptr, 16); map->values = NULL; } /* listmap_init */ @@ -200,7 +222,8 @@ static void listmap_init(listmap_t *map) { * * @param map the listmap */ -static void listmap_term(listmap_t *map) { +static void listmap_term(listmap_t *map) +{ del_set(map->map); } /* listmap_term */ @@ -212,13 +235,14 @@ static void listmap_term(listmap_t *map) { * * @return the associated listmap entry for the given id */ -static listmap_entry_t *listmap_find(listmap_t *map, void *id) { +static listmap_entry_t *listmap_find(listmap_t *map, void *id) +{ listmap_entry_t key, *entry; key.id = id; key.list = NULL; key.next = NULL; - entry = set_insert(map->map, &key, sizeof(key), HASH_PTR(id)); + entry = (listmap_entry_t*)set_insert(map->map, &key, sizeof(key), HASH_PTR(id)); if (entry->list == NULL) { /* a new entry, put into the list */ @@ -235,32 +259,36 @@ static listmap_entry_t *listmap_find(listmap_t *map, void *id) { * * @return a hash value for the given opcode map entry */ -static unsigned opcode_hash(const opcode_key_t *entry) { - return (entry->mode - (ir_mode *)0) * 9 + entry->code + entry->u.proj * 3 + HASH_PTR(entry->u.ent) + entry->arity; +static unsigned opcode_hash(const opcode_key_t *entry) +{ + /* assume long >= int */ + return (unsigned)(PTR_TO_INT(entry->mode) * 9 + entry->code + entry->u.proj * 3 + HASH_PTR(entry->u.addr) + entry->arity); } /* opcode_hash */ /** * Compare two entries in the opcode map. */ -static int cmp_opcode(const void *elt, const void *key, size_t size) { - const opcode_key_t *o1 = elt; - const opcode_key_t *o2 = key; +static int cmp_opcode(const void *elt, const void *key, size_t size) +{ + const opcode_key_t *o1 = (opcode_key_t*)elt; + const opcode_key_t *o2 = (opcode_key_t*)key; (void) size; return o1->code != o2->code || o1->mode != o2->mode || o1->arity != o2->arity || - o1->u.proj != o2->u.proj || o1->u.ent != o2->u.ent; + o1->u.proj != o2->u.proj || o1->u.addr != o2->u.addr; } /* cmp_opcode */ /** * Creates a new empty partition and put in on the * partitions list. * - * @param meet_block the control flow meet block of thi partition + * @param meet_block the control flow meet block of this partition * @param env the environment */ -static partition_t *create_partition(ir_node *meet_block, environment_t *env) { - partition_t *part = obstack_alloc(&env->obst, sizeof(*part)); +static partition_t *create_partition(ir_node *meet_block, environment_t *env) +{ + partition_t *part = OALLOC(&env->obst, partition_t); INIT_LIST_HEAD(&part->blocks); part->meet_block = meet_block; @@ -274,11 +302,13 @@ static partition_t *create_partition(ir_node *meet_block, environment_t *env) { * Allocate a new block in the given partition. * * @param block the IR-node + * @param meet_input Input number of this block in the meet-block * @param partition the partition to add to * @param env the environment */ -static block_t *create_block(ir_node *block, partition_t *partition, environment_t *env) { - block_t *bl = obstack_alloc(&env->obst, sizeof(*bl)); +static block_t *create_block(ir_node *block, int meet_input, partition_t *partition, environment_t *env) +{ + block_t *bl = OALLOC(&env->obst, block_t); set_irn_link(block, bl); @@ -289,6 +319,7 @@ static block_t *create_block(ir_node *block, partition_t *partition, environment bl->cf_root = NULL; bl->input_pairs = NULL; bl->phis = NULL; + bl->meet_input = meet_input; /* put it into the list of partition blocks */ list_add_tail(&bl->block_list, &partition->blocks); @@ -308,8 +339,9 @@ static block_t *create_block(ir_node *block, partition_t *partition, environment * @param block the block to add to * @param env the environment */ -static node_t *create_node(ir_node *irn, block_t *block, environment_t *env) { - node_t *node = obstack_alloc(&env->obst, sizeof(*node)); +static node_t *create_node(ir_node *irn, block_t *block, environment_t *env) +{ + node_t *node = OALLOC(&env->obst, node_t); node->node = irn; node->is_input = 0; @@ -327,8 +359,9 @@ static node_t *create_node(ir_node *irn, block_t *block, environment_t *env) { * @param idx the index of the block input in node's predecessors * @param env the environment */ -static void add_pair(block_t *block, ir_node *irn, int idx, environment_t *env) { - pair_t *pair = obstack_alloc(&env->obst, sizeof(*pair)); +static void add_pair(block_t *block, ir_node *irn, int idx, environment_t *env) +{ + pair_t *pair = OALLOC(&env->obst, pair_t); pair->next = block->input_pairs; pair->irn = irn; @@ -345,8 +378,9 @@ static void add_pair(block_t *block, ir_node *irn, int idx, environment_t *env) * @param phi the Phi node * @param env the environment */ -static void add_phi(block_t *block, ir_node *phi, environment_t *env) { - phi_t *node = obstack_alloc(&env->obst, sizeof(*node)); +static void add_phi(block_t *block, ir_node *phi, environment_t *env) +{ + phi_t *node = OALLOC(&env->obst, phi_t); node->next = block->phis; node->phi = phi; @@ -358,7 +392,8 @@ static void add_phi(block_t *block, ir_node *phi, environment_t *env) { /** * Creates an opcode from a node. */ -static opcode_key_t *opcode(const node_t *node, environment_t *env) { +static opcode_key_t *opcode(const node_t *node, environment_t *env) +{ opcode_key_t key, *entry; ir_node *irn = node->node; @@ -373,7 +408,7 @@ static opcode_key_t *opcode(const node_t *node, environment_t *env) { } key.mode = get_irn_mode(node->node); key.u.proj = 0; - key.u.ent = NULL; + key.u.addr = NULL; switch (key.code) { case iro_Proj: @@ -382,11 +417,29 @@ static opcode_key_t *opcode(const node_t *node, environment_t *env) { case iro_Sel: key.u.ent = get_Sel_entity(irn); break; + case iro_SymConst: + key.u.sym = get_SymConst_symbol(irn); + break; + case iro_Const: + key.u.tv = get_Const_tarval(irn); + break; + case iro_Conv: + key.u.intVal = get_Conv_strict(irn); + break; + case iro_Load: + key.mode = get_Load_mode(irn); + break; + case iro_Div: + key.u.intVal = get_Div_no_remainder(irn); + break; + case iro_Builtin: + key.u.intVal = get_Builtin_kind(irn); + break; default: break; } - entry = set_insert(env->opcode2id_map, &key, sizeof(key), opcode_hash(&key)); + entry = (opcode_key_t*)set_insert(env->opcode2id_map, &key, sizeof(key), opcode_hash(&key)); return entry; } /* opcode */ @@ -399,7 +452,8 @@ static opcode_key_t *opcode(const node_t *node, environment_t *env) { * * @return a new partition containing the nodes of g */ -static partition_t *split(partition_t *Z, block_t *g, environment_t *env) { +static partition_t *split(partition_t *Z, block_t *g, environment_t *env) +{ partition_t *Z_prime; block_t *block; unsigned n = 0; @@ -429,13 +483,29 @@ static partition_t *split(partition_t *Z, block_t *g, environment_t *env) { return Z_prime; } /* split */ +/** + * Return non-zero if pred should be tread as a input node. + */ +static int is_input_node(ir_node *pred, ir_node *irn, int index) +{ + /* for now, do NOT turn direct calls into indirect one */ + if (index != 1) + return 1; + if (! is_SymConst_addr_ent(pred)) + return 1; + if (! is_Call(irn)) + return 1; + return 0; +} /* is_input_node */ + /** * Propagate nodes on all wait queues of the given partition. * * @param part the partition - * @param env the environment + * @param env the environment */ -void propagate_blocks(partition_t *part, environment_t *env) { +static void propagate_blocks(partition_t *part, environment_t *env) +{ block_t *ready_blocks = NULL; unsigned n_ready = 0; block_t *bl, *next; @@ -444,7 +514,7 @@ void propagate_blocks(partition_t *part, environment_t *env) { DB((dbg, LEVEL_2, " Propagate blocks on part%u\n", part->nr)); - /* Let map be an empty mapping from the range of Opcodes to (local) list of Nodes. */ + /* Let map be an empty mapping from the range of Opcodes to (local) list of blocks. */ listmap_init(&map); list_for_each_entry_safe(block_t, bl, next, &part->blocks, block_list) { opcode_key_t *id; @@ -477,11 +547,14 @@ void propagate_blocks(partition_t *part, environment_t *env) { if (block != bl->block) { p_node = create_node(pred, bl, env); - /* do not threat Constants like live-ins */ - if (! is_irn_constlike(pred)) { + if (is_input_node(pred, irn, i)) { + /* is a block live input */ p_node->is_input = 1; if (! is_Phi(irn)) add_pair(bl, irn, i, env); + } else if (is_Phi(pred)) { + /* update the Phi list */ + add_phi(bl, pred, env); } } else if (! irn_visited_else_mark(pred)) { /* not yet visited, ok */ @@ -497,7 +570,7 @@ void propagate_blocks(partition_t *part, environment_t *env) { DB((dbg, LEVEL_3, " propagate Input %+F\n", node->node)); } - /* Add bl to map[opcode(bl)]. */ + /* Add bl to map[opcode(n)]. */ id = opcode(node, env); entry = listmap_find(&map, id); bl->next = entry->list; @@ -543,7 +616,8 @@ void propagate_blocks(partition_t *part, environment_t *env) { * * @param env the environment */ -void propagate(environment_t *env) { +static void propagate(environment_t *env) +{ partition_t *part, *next; list_for_each_entry_safe(partition_t, part, next, &env->partitions, part_list) { @@ -556,6 +630,92 @@ void propagate(environment_t *env) { } } /* propagate */ +/** + * Map a block to the phi[block->input] live-trough. + */ +static void *live_throughs(const block_t *bl, const ir_node *phi) +{ + ir_node *input = get_Phi_pred(phi, bl->meet_input); + + /* If this input is inside our block, this + is a live-out and not a live trough. + Live-outs are tested inside propagate, so map all of + them to the "general" value NULL */ + if (get_nodes_block(input) == bl->block) + return NULL; + return input; +} /* live_throughs */ + +/** + * Split partition by live-outs and live-troughs. + * + * @param part the partition + * @param env the environment + */ +static void propagate_blocks_live_troughs(partition_t *part, environment_t *env) +{ + const ir_node *meet_block = part->meet_block; + block_t *bl, *next; + listmap_t map; + listmap_entry_t *iter; + const ir_node *phi; + + DB((dbg, LEVEL_2, " Propagate live-troughs on part%u\n", part->nr)); + + for (phi = get_Block_phis(meet_block); phi != NULL; phi = get_Phi_next(phi)) { + /* propagate on all Phis of the meet-block */ + + if (part->n_blocks < 2) { + /* zero or one block left, kill this partition */ + list_del(&part->part_list); + DB((dbg, LEVEL_2, " Partition %u contains less than 2 blocks, killed\n", part->nr)); + return; + } + + /* Let map be an empty mapping from the range of live-troughs to (local) list of blocks. */ + listmap_init(&map); + list_for_each_entry_safe(block_t, bl, next, &part->blocks, block_list) { + opcode_key_t *id; + listmap_entry_t *entry; + + /* Add bl to map[live_trough(bl)]. */ + id = (opcode_key_t*)live_throughs(bl, phi); + entry = listmap_find(&map, id); + bl->next = entry->list; + entry->list = bl; + } + + /* for all sets S except one in the range of map do */ + for (iter = map.values; iter != NULL; iter = iter->next) { + block_t *S; + + if (iter->next == NULL) { + /* this is the last entry, ignore */ + break; + } + S = iter->list; + + /* Add SPLIT( X, S ) to P. */ + split(part, S, env); + } + listmap_term(&map); + } +} /* propagate_blocks_live_troughs */ + +/** + * Propagate live-troughs on all partitions on the partition list. + * + * @param env the environment + */ +static void propagate_live_troughs(environment_t *env) +{ + partition_t *part, *next; + + list_for_each_entry_safe(partition_t, part, next, &env->partitions, part_list) { + propagate_blocks_live_troughs(part, env); + } +} /* propagate_live_troughs */ + /** * Apply analysis results by replacing all blocks of a partition * by one representative. @@ -567,7 +727,8 @@ void propagate(environment_t *env) { * * @param part the partition to process */ -static void apply(ir_graph *irg, partition_t *part) { +static void apply(ir_graph *irg, partition_t *part) +{ block_t *repr = list_entry(part->blocks.next, block_t, block_list); block_t *bl; ir_node *block, *end, *meet_block, *p, *next; @@ -690,7 +851,7 @@ static void apply(ir_graph *irg, partition_t *part) { if (is_op_forking(cfop)) { /* a critical edge */ ir_node *block = new_r_Block(irg, 1, &ins[i]); - ir_node *jmp = new_r_Jmp(irg, block); + ir_node *jmp = new_r_Jmp(block); ins[i] = jmp; } } @@ -709,7 +870,7 @@ static void apply(ir_graph *irg, partition_t *part) { for (repr_pair = repr->input_pairs; repr_pair != NULL; repr_pair = repr_pair->next) { ir_node *input = get_irn_n(repr_pair->irn, repr_pair->index); ir_mode *mode = get_irn_mode(input); - ir_node *phi = new_r_Phi(current_ir_graph, block, n, repr_pair->ins, mode); + ir_node *phi = new_r_Phi(block, n, repr_pair->ins, mode); set_irn_n(repr_pair->irn, repr_pair->index, phi); DEL_ARR_F(repr_pair->ins); @@ -766,50 +927,21 @@ continue_outer: set_irn_in(p, j, &phi_ins[k * n]); } } + DEL_ARR_F(phi_ins); /* fix inputs of the meet block */ set_irn_in(meet_block, j, ins); DEL_ARR_F(ins); } /* apply */ -/** - * Create a partition for a given meet block. - * - * @param block the meet block - * @param preds array of candidate predecessors - * @param n_preds number of elements in preds - * @param env the environment - */ -static void partition_for_block(ir_node *block, ir_node *preds[], int n_preds, environment_t *env) { - partition_t *part = create_partition(block, env); - int i; - - for (i = n_preds - 1; i >= 0; --i) { - ir_node *pred = preds[i]; - ir_node *block; - block_t *bl; - node_t *node; - - mark_irn_visited(pred); - - block = get_nodes_block(pred); - bl = create_block(block, part, env); - node = create_node(pred, bl, env); - - bl->cf_root = node; - } - - dump_partition("Created", part); -} /* partition_for_block */ - - /** * Create a partition for a the end block. * * @param end_block the end block * @param env the environment */ -static void partition_for_end_block(ir_node *end_block, environment_t *env) { +static void partition_for_end_block(ir_node *end_block, environment_t *env) +{ partition_t *part = create_partition(end_block, env); ir_node *end; int i; @@ -824,14 +956,14 @@ static void partition_for_end_block(ir_node *end_block, environment_t *env) { mark_irn_visited(pred); block = get_nodes_block(pred); - bl = create_block(block, part, env); + bl = create_block(block, i, part, env); node = create_node(pred, bl, env); bl->cf_root = node; } /* collect all no-return blocks */ - end = get_irg_end(current_ir_graph); + end = get_irg_end(get_irn_irg(end_block)); for (i = get_End_n_keepalives(end) - 1; i >= 0; --i) { ir_node *ka = get_End_keepalive(end, i); ir_node *block; @@ -844,7 +976,7 @@ static void partition_for_end_block(ir_node *end_block, environment_t *env) { /* found one */ block = get_nodes_block(ka); - bl = create_block(block, part, env); + bl = create_block(block, -1, part, env); node = create_node(ka, bl, env); bl->cf_root = node; @@ -853,11 +985,45 @@ static void partition_for_end_block(ir_node *end_block, environment_t *env) { dump_partition("Created", part); } /* partition_for_end_block */ +#ifdef GENERAL_SHAPE +/** + * Create a partition for a given meet block. + * + * @param block the meet block + * @param preds array of candidate predecessors + * @param n_preds number of elements in preds + * @param env the environment + */ +static void partition_for_block(ir_node *block, pred_t preds[], int n_preds, environment_t *env) +{ + partition_t *part = create_partition(block, env); + int i; + + for (i = n_preds - 1; i >= 0; --i) { + ir_node *pred = preds[i].pred; + ir_node *block; + block_t *bl; + node_t *node; + + mark_irn_visited(pred); + + block = get_nodes_block(pred); + bl = create_block(block, preds[i].index, part, env); + node = create_node(pred, bl, env); + + bl->cf_root = node; + } + + dump_partition("Created", part); +} /* partition_for_block */ + /** * Walker: clear the links of all block phi lists and normal * links. */ -static void clear_phi_links(ir_node *irn, void *env) { +static void clear_phi_links(ir_node *irn, void *env) +{ + (void) env; if (is_Block(irn)) { set_Block_phis(irn, NULL); set_irn_link(irn, NULL); @@ -865,10 +1031,11 @@ static void clear_phi_links(ir_node *irn, void *env) { } /* clear_phi_links */ /** - * Walker, detect live-out only nodes. + * Walker, detect live-out nodes. */ -static void find_liveouts(ir_node *irn, void *ctx) { - environment_t *env = ctx; +static void find_liveouts(ir_node *irn, void *ctx) +{ + environment_t *env = (environment_t*)ctx; ir_node **live_outs = env->live_outs; ir_node *this_block; int i; @@ -892,31 +1059,30 @@ static void find_liveouts(ir_node *irn, void *ctx) { ir_node *pred = get_irn_n(irn, i); int idx = get_irn_idx(pred); - if (live_outs[idx] == pred) { - /* referenced by other nodes inside this block */ + if (live_outs[idx] != NULL) { + /* already marked as live-out */ return; } pred_block = get_nodes_block(pred); - if (this_block != pred_block) { + /* Phi nodes always refer to live-outs */ + if (is_Phi(irn) || this_block != pred_block) { /* pred is a live-out */ live_outs[idx] = pred_block; - } else { - /* this node is referenced from inside this block */ - live_outs[idx] = pred; } } -} +} /* find_liveouts */ /** * Check if the current block is the meet block of a its predecessors. */ -static void check_for_cf_meet(ir_node *block, void *ctx) { - environment_t *env = ctx; +static void check_for_cf_meet(ir_node *block, void *ctx) +{ + environment_t *env = (environment_t*)ctx; int i, k, n; - ir_node **preds; + pred_t *preds; - if (block == get_irg_end_block(current_ir_graph)) { + if (block == get_irg_end_block(get_irn_irg(block))) { /* always create a partition for the end block */ partition_for_end_block(block, env); return; @@ -927,16 +1093,21 @@ static void check_for_cf_meet(ir_node *block, void *ctx) { /* Must have at least two predecessors */ return; } - NEW_ARR_A(ir_node *, preds, n); + NEW_ARR_A(pred_t, preds, n); k = 0; for (i = n - 1; i >= 0; --i) { ir_node *pred = get_Block_cfgpred(block, i); + ir_node *pred_block; /* pred must be a direct jump to us */ - if (! is_Jmp(pred) && ! is_Raise(pred)) + if (! is_Jmp(pred) && ! is_Raise(pred) && !is_Bad(pred)) continue; - preds[k++] = pred; + + pred_block = get_nodes_block(skip_Proj(pred)); + + preds[k].pred = pred; + preds[k].index = i; } if (k > 1) @@ -946,13 +1117,16 @@ static void check_for_cf_meet(ir_node *block, void *ctx) { /** * Compare two nodes for root ordering. */ -static int cmp_nodes(const void *a, const void *b) { - const ir_node *irn_a = a; - const ir_node *irn_b = b; - ir_opcode code_a = get_irn_opcode(irn_a); - ir_opcode code_b = get_irn_opcode(irn_b); - ir_mode *mode_a, *mode_b; - unsigned idx_a, idx_b; +static int cmp_nodes(const void *a, const void *b) +{ + const ir_node *const *pa = (const ir_node*const*)a; + const ir_node *const *pb = (const ir_node*const*)b; + const ir_node *irn_a = *pa; + const ir_node *irn_b = *pb; + unsigned code_a = get_irn_opcode(irn_a); + unsigned code_b = get_irn_opcode(irn_b); + ir_mode *mode_a, *mode_b; + unsigned idx_a, idx_b; /* try opcode first */ if (code_a != code_b) @@ -975,7 +1149,8 @@ static int cmp_nodes(const void *a, const void *b) { /** * Add the roots to all blocks. */ -static void add_roots(ir_graph *irg, environment_t *env) { +static void add_roots(ir_graph *irg, environment_t *env) +{ unsigned idx, n = get_irg_last_idx(irg); ir_node **live_outs = env->live_outs; block_t *bl; @@ -997,10 +1172,10 @@ static void add_roots(ir_graph *irg, environment_t *env) { } /* * Now sort the roots to normalize them as good as possible. - * Else, we will split identical blocks if we start which different roots + * Else, we will split identical blocks if we start which different roots. */ for (bl = env->all_blocks; bl != NULL; bl = bl->all_next) { - int i, n = ARR_LEN(bl->roots); + size_t i, n = ARR_LEN(bl->roots); #if 1 /* TODO: is this really needed? The roots are already in @@ -1019,20 +1194,18 @@ static void add_roots(ir_graph *irg, environment_t *env) { bl->roots = NULL; } } /* add_roots */ +#endif /* GENERAL_SHAPE */ /* Combines congruent end blocks into one. */ -int shape_blocks(ir_graph *irg) { - ir_graph *rem; +int shape_blocks(ir_graph *irg) +{ environment_t env; partition_t *part; + block_t *bl; int res, n; - rem = current_ir_graph; - current_ir_graph = irg; - /* register a debug mask */ FIRM_DBG_REGISTER(dbg, "firm.opt.blocks"); - firm_dbg_set_mask(dbg, 7); DEBUG_ONLY(part_nr = 0); DB((dbg, LEVEL_1, "Shaping blocks for %+F\n", irg)); @@ -1053,15 +1226,18 @@ int shape_blocks(ir_graph *irg) { ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_PHI_LIST); +#ifdef GENERAL_SHAPE /* * Detect, which nodes are live-out only: these are the roots of our blocks. * Build phi lists. */ irg_walk_graph(irg, clear_phi_links, find_liveouts, &env); +#endif ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED); inc_irg_visited(irg); +#ifdef GENERAL_SHAPE /* * Detect all control flow meets and create partitions. */ @@ -1069,11 +1245,17 @@ int shape_blocks(ir_graph *irg) { /* add root nodes to the partition blocks */ add_roots(irg, &env); +#else + partition_for_end_block(get_irg_end_block(irg), &env); +#endif + propagate_live_troughs(&env); while (! list_empty(&env.partitions)) propagate(&env); res = !list_empty(&env.ready); + //if (res) dump_ir_block_graph(irg, "-before"); + list_for_each_entry(partition_t, part, &env.ready, part_list) { dump_partition("Ready Partition", part); @@ -1086,16 +1268,24 @@ int shape_blocks(ir_graph *irg) { set_irg_outs_inconsistent(irg); set_irg_extblk_inconsistent(irg); set_irg_doms_inconsistent(irg); - /* Hmm, only the root loop is inconsistent */ set_irg_loopinfo_inconsistent(irg); /* Calls might be removed. */ set_trouts_inconsistent(); } + for (bl = env.all_blocks; bl != NULL; bl = bl->all_next) { + DEL_ARR_F(bl->roots); + } + + DEL_ARR_F(env.live_outs); del_set(env.opcode2id_map); obstack_free(&env.obst, NULL); - current_ir_graph = rem; return res; } /* shape_blocks */ + +ir_graph_pass_t *shape_blocks_pass(const char *name) +{ + return def_graph_pass_ret(name ? name : "shape_blocks", shape_blocks); +} /* shape_blocks_pass */