2 * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
6 * This file may be distributed and/or modified under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation and appearing in the file LICENSE.GPL included in the
9 * packaging of this file.
11 * Licensees holding valid libFirm Professional Edition licenses may use
12 * this file in accordance with the libFirm Commercial License.
13 * Agreement provided with the Software.
15 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * @brief Combining congruent blocks
23 * @author Michael Beck
26 * This phase find congruent blocks. Works currently for
27 * predecessors of the end block only.
28 * Two block are congruent, if they contains only equal calculations.
31 #include "irgraph_t.h"
37 typedef struct partition_t partition_t;
38 typedef struct block_t block_t;
39 typedef struct node_t node_t;
40 typedef struct opcode_key_t opcode_key_t;
41 typedef struct listmap_entry_t listmap_entry_t;
42 typedef struct environment_t environment_t;
44 /** An opcode map key. */
46 ir_opcode code; /**< The Firm opcode. */
47 ir_mode *mode; /**< The mode of all nodes in the partition. */
48 int arity; /**< The arity of this opcode (needed for Phi etc. */
50 long proj; /**< For Proj nodes, its proj number */
51 ir_entity *ent; /**< For Sel Nodes, its entity */
55 /** A partition contains all congruent blocks. */
57 list_head part_list; /**< Double linked list of partitions. */
58 list_head blocks; /**< List of blocks in this partition. */
59 unsigned n_blocks; /**< Number of block in this partition. */
61 unsigned nr; /**< For debugging: number of this partition. */
67 list_head block_list; /**< Double linked list of block inside a partition. */
68 list_head nodes; /**< Wait-queue of nodes that must be checked for congruence. */
69 block_t *next; /**< Next block of a split list. */
70 ir_node *block; /**< Pointer to the associated IR-node block. */
71 node_t **roots; /**< The array of the root nodes. */
76 list_head node_list; /**< Double linked list of block inside a partition. */
77 ir_node *node; /**< Pointer to the associated IR-node or NULL for block inputs. */
78 char is_input; /**< Set if this node is an input from other block. */
81 /** The environment. */
82 typedef struct environment_t {
83 list_head partitions; /**< list of partitions. */
84 list_head ready; /**< list of ready partitions. */
85 set *opcode2id_map; /**< The opcodeMode->id map. */
86 struct obstack obst; /** obstack for temporary data */
90 * An entry in the list_map.
92 struct listmap_entry_t {
93 void *id; /**< The id. */
94 block_t *list; /**< The associated list for this id. */
95 listmap_entry_t *next; /**< Link to the next entry in the map. */
98 /** We must map id's to lists. */
99 typedef struct listmap_t {
100 set *map; /**< Map id's to listmap_entry_t's */
101 listmap_entry_t *values; /**< List of all values in the map. */
104 #define get_irn_node(irn) ((node_t *)get_irn_link(irn))
105 #define set_irn_node(irn, node) set_irn_link(irn, node)
106 #define get_irn_block(irn) ((block_t *)get_irn_link(irn))
107 #define set_irn_block(irn, block) set_irn_link(irn, block)
109 /** The debug module handle. */
110 DEBUG_ONLY(static firm_dbg_module_t *dbg;)
112 /** Next partition number. */
113 DEBUG_ONLY(static unsigned part_nr = 0);
117 * Dump partition to output.
119 static void dump_partition(const char *msg, const partition_t *part) {
120 const block_t *block;
123 DB((dbg, LEVEL_2, "%s part%u (%u) {\n ", msg, part->nr, part->n_blocks));
124 list_for_each_entry(block_t, block, &part->blocks, block_list) {
125 DB((dbg, LEVEL_2, "%s%+F", first ? "" : ", ", block->block));
128 DB((dbg, LEVEL_2, "\n}\n"));
129 } /* dump_partition */
134 static void dump_list(const char *msg, const block_t *block) {
138 DB((dbg, LEVEL_3, "%s = {\n ", msg));
139 for (p = block; p != NULL; p = p->next) {
140 DB((dbg, LEVEL_3, "%s%+F", first ? "" : ", ", p->block));
143 DB((dbg, LEVEL_3, "\n}\n"));
146 #define dump_partition(msg, part)
147 #define dump_list(msg, block)
151 * Compare two pointer values of a listmap.
153 static int listmap_cmp_ptr(const void *elt, const void *key, size_t size) {
154 const listmap_entry_t *e1 = elt;
155 const listmap_entry_t *e2 = key;
158 return e1->id != e2->id;
159 } /* listmap_cmp_ptr */
162 * Initializes a listmap.
164 * @param map the listmap
166 static void listmap_init(listmap_t *map) {
167 map->map = new_set(listmap_cmp_ptr, 16);
172 * Terminates a listmap.
174 * @param map the listmap
176 static void listmap_term(listmap_t *map) {
181 * Return the associated listmap entry for a given id.
183 * @param map the listmap
184 * @param id the id to search for
186 * @return the associated listmap entry for the given id
188 static listmap_entry_t *listmap_find(listmap_t *map, void *id) {
189 listmap_entry_t key, *entry;
194 entry = set_insert(map->map, &key, sizeof(key), HASH_PTR(id));
196 if (entry->list == NULL) {
197 /* a new entry, put into the list */
198 entry->next = map->values;
205 * Calculate the hash value for an opcode map entry.
207 * @param entry an opcode map entry
209 * @return a hash value for the given opcode map entry
211 static unsigned opcode_hash(const opcode_key_t *entry) {
212 return (entry->mode - (ir_mode *)0) * 9 + entry->code + entry->u.proj * 3 + HASH_PTR(entry->u.ent) + entry->arity;
216 * Compare two entries in the opcode map.
218 static int cmp_opcode(const void *elt, const void *key, size_t size) {
219 const opcode_key_t *o1 = elt;
220 const opcode_key_t *o2 = key;
223 return o1->code != o2->code || o1->mode != o2->mode ||
224 o1->arity != o2->arity ||
225 o1->u.proj != o2->u.proj || o1->u.ent != o2->u.ent;
229 * Creates a new empty partition.
231 static partition_t *create_partition(environment_t *env) {
232 partition_t *part = obstack_alloc(&env->obst, sizeof(*part));
234 INIT_LIST_HEAD(&part->blocks);
236 DEBUG_ONLY(part->nr = part_nr++);
237 list_add_tail(&part->part_list, &env->partitions);
239 } /* create_partition */
242 * Allocate a new block.
244 * @param block the IR-node
245 * @param env the environment
247 static block_t *create_block(ir_node *block, environment_t *env) {
248 block_t *bl = obstack_alloc(&env->obst, sizeof(*bl));
250 INIT_LIST_HEAD(&bl->nodes);
254 set_irn_block(block, bl);
259 * Adds a block to a partition.
261 * @param partition the partition to add to
262 * @param block the block to add
264 static void add_block(partition_t *partition, block_t *block) {
265 list_add_tail(&block->block_list, &partition->blocks);
266 ++partition->n_blocks;
270 * Allocate a new node.
272 * @param irn the IR-node
273 * @param env the environment
275 static node_t *create_node(ir_node *irn, environment_t *env) {
276 node_t *node = obstack_alloc(&env->obst, sizeof(*node));
284 * Adds a node to a block wait queue.
286 * @param block the block to add to
287 * @param node the node to add
289 static void add_node(block_t *block, node_t *node) {
290 list_add_tail(&node->node_list, &block->nodes);
293 /** creates an opcode */
294 static opcode_key_t *opcode(const node_t *node, environment_t *env) {
295 opcode_key_t key, *entry;
296 ir_node *irn = node->node;
298 if (node->is_input) {
299 /* Node: as Block nodes are never propagated, it is safe to
300 use its code for "input" node */
301 key.code = iro_Block;
304 key.code = get_irn_opcode(irn);
305 key.arity = get_irn_arity(irn);
307 key.mode = get_irn_mode(node->node);
313 key.u.proj = get_Proj_proj(irn);
316 key.u.ent = get_Sel_entity(irn);
322 entry = set_insert(env->opcode2id_map, &key, sizeof(key), opcode_hash(&key));
327 * Split a partition by a local list.
329 * @param Z partition to split
330 * @param g a (non-empty) block list
331 * @param env the environment
333 * @return a new partition containing the nodes of g
335 static partition_t *split(partition_t *Z, block_t *g, environment_t *env) {
336 partition_t *Z_prime;
340 dump_partition("Splitting ", Z);
341 dump_list("by list ", g);
345 /* Remove g from Z. */
346 for (block = g; block != NULL; block = block->next) {
347 list_del(&block->block_list);
350 assert(n < Z->n_blocks);
353 /* Move g to a new partition, Z'. */
354 Z_prime = create_partition(env);
355 for (block = g; block != NULL; block = block->next) {
356 list_add_tail(&block->block_list, &Z_prime->blocks);
358 Z_prime->n_blocks = n;
360 dump_partition("Now ", Z);
361 dump_partition("Created new ", Z_prime);
366 * Propagate nodes on all wait queues of the given partition.
368 * @param part the partition
369 * @param env the environment
371 void propagate_blocks(partition_t *part, environment_t *env) {
372 block_t *ready_blocks = NULL;
373 unsigned n_ready = 0;
376 listmap_entry_t *iter;
378 DB((dbg, LEVEL_2, "Propagate blocks on part%u\n", part->nr));
380 /* Let map be an empty mapping from the range of Opcodes to (local) list of Nodes. */
382 list_for_each_entry_safe(block_t, bl, next, &part->blocks, block_list) {
384 listmap_entry_t *entry;
387 if (list_empty(&bl->nodes)) {
388 bl->next = ready_blocks;
391 DB((dbg, LEVEL_1, "Block %+F ready\n", bl->block));
395 /* get the first node from the wait queue */
396 node = list_entry(bl->nodes.next, node_t, node_list);
397 list_del(&node->node_list);
399 /* put all not-visited predecessors to the wait queue */
400 if (! node->is_input) {
401 ir_node *irn = node->node;
404 DB((dbg, LEVEL_3, " propagate %+F\n", node->node));
405 ir_normalize_node(node->node);
406 for (i = get_irn_arity(irn) - 1; i >= 0; --i) {
407 ir_node *pred = get_irn_n(irn, i);
408 ir_node *block = get_nodes_block(skip_Proj(pred));
411 if (block != bl->block) {
412 p_node = create_node(pred, env);
413 p_node->is_input = 1;
414 add_node(bl, p_node);
415 } else if (! irn_visited_else_mark(pred)) {
416 /* not yet visited, ok */
417 p_node = create_node(pred, env);
418 set_irn_node(pred, p_node);
419 add_node(bl, p_node);
423 DB((dbg, LEVEL_3, " propagate Input %+F\n", node->node));
426 /* Add bl to map[opcode(bl)]. */
427 id = opcode(node, env);
428 entry = listmap_find(&map, id);
429 bl->next = entry->list;
433 /* split out ready blocks */
437 if (n_ready < part->n_blocks)
438 Z = split(part, ready_blocks, env);
441 list_del(&Z->part_list);
443 if (Z->n_blocks > 1) {
444 DB((dbg, LEVEL_1, "Partition %u is ready\n", Z->nr));
445 list_add(&Z->part_list, &env->ready);
447 DB((dbg, LEVEL_1, "Partition %u contains only one block, killed\n", Z->nr));
451 /* for all sets S except one in the range of map do */
452 for (iter = map.values; iter != NULL; iter = iter->next) {
455 if (iter->next == NULL) {
456 /* this is the last entry, ignore */
461 /* Add SPLIT( X, S ) to P. */
465 } /* propagate_blocks */
468 * Propagate nodes on all wait queues.
470 * @param env the environment
472 void propagate(environment_t *env) {
473 partition_t *part, *next;
475 list_for_each_entry_safe(partition_t, part, next, &env->partitions, part_list) {
476 if (part->n_blocks == 1) {
477 /* only one block left, move to ready */
478 list_del(&part->part_list);
479 DB((dbg, LEVEL_1, "Partition %u contains only one block, killed\n", part->nr));
481 propagate_blocks(part, env);
485 void melt_end_blocks(ir_graph *irg) {
492 rem = current_ir_graph;
493 current_ir_graph = irg;
495 /* register a debug mask */
496 FIRM_DBG_REGISTER(dbg, "firm.opt.blocks");
497 firm_dbg_set_mask(dbg, SET_LEVEL_3);
499 DB((dbg, LEVEL_1, "Melting end blocks for %+F\n", irg));
501 ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_IRN_VISITED);
502 inc_irg_visited(irg);
504 obstack_init(&env.obst);
505 INIT_LIST_HEAD(&env.partitions);
506 INIT_LIST_HEAD(&env.ready);
507 env.opcode2id_map = new_set(cmp_opcode, iro_Last * 4);
509 part = create_partition(&env);
511 /* collect all no-return blocks */
512 end = get_irg_end(irg);
513 for (i = get_End_n_keepalives(end) - 1; i >= 0; --i) {
514 ir_node *ka = get_End_keepalive(end, i);
521 mark_irn_visited(ka);
524 block = get_nodes_block(ka);
525 bl = create_block(block, &env);
527 node = create_node(ka, &env);
530 /* currently we support only one root */
531 bl->roots = NEW_ARR_D(node_t*, &env.obst, 1);
535 /* collect normal blocks */
536 end = get_irg_end_block(irg);
537 for (i = get_Block_n_cfgpreds(end) - 1; i >= 0; --i) {
538 ir_node *pred = get_Block_cfgpred(end, i);
543 mark_irn_visited(pred);
545 block = get_nodes_block(pred);
546 bl = create_block(block, &env);
548 node = create_node(pred, &env);
551 /* currently we support only one root */
552 bl->roots = NEW_ARR_D(node_t*, &env.obst, 1);
556 while (! list_empty(&env.partitions))
559 list_for_each_entry(partition_t, part, &env.ready, part_list) {
560 dump_partition("Ready Partition", part);
562 ir_free_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_IRN_VISITED);
563 del_set(env.opcode2id_map);
564 obstack_free(&env.obst, NULL);
565 current_ir_graph = rem;
566 } /* melt_end_blocks */