3 * File name: ir/opt/opt_osr.
4 * Purpose: Operator Strength Reduction,
5 * Keith D. Cooper, L. Taylor Simpson, Christopher A. Vick
10 * Copyright: (c) 2006 Universität Karlsruhe
11 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
36 /** The debug handle. */
37 DEBUG_ONLY(static firm_dbg_module_t *dbg;)
39 /* Use the link field to mark IV's */
40 #define MARK_LOOP_IV(loop) set_loop_link((loop), (loop))
41 #define UNMARK_LOOP_IV(loop) set_loop_link((loop), NULL)
42 #define IS_LOOP_IV(loop) (get_loop_link(loop) != NULL)
46 ir_node *head; /**< the head of the list */
47 ir_node *header; /**< the header block of this scc */
48 int is_iv; /**< true, if this scc is an IV */
52 typedef struct node_entry {
53 unsigned DFSnum; /**< the DFS number of this node */
54 unsigned low; /**< the low number of this node */
55 ir_node *header; /**< the header of this node */
56 int in_stack; /**< flag, set if the node is on the stack */
57 ir_node *next; /**< link to the next node the the same scc */
58 scc *pscc; /**< the scc of this node */
59 unsigned POnum; /**< the post order number for blocks */
62 /** The environment. */
63 typedef struct iv_env {
64 node_entry *entries; /**< the node entry array */
65 struct obstack obst; /**< an obstack for allocations */
66 ir_node **stack; /**< the node stack */
67 int tos; /**< tos index */
68 unsigned nextDFSnum; /**< the current DFS number */
69 unsigned replaced; /**< number of replaced ops */
70 unsigned POnum; /**< current post order number */
74 * Check if irn is an IV.
76 static scc *is_iv(ir_node *irn, iv_env *env) {
77 int idx = get_irn_idx(irn);
78 node_entry *e = &env->entries[idx];
80 return e->pscc && e->pscc->is_iv ? e->pscc : NULL;
84 * Check if irn is a region constant.
86 static int is_rc(ir_node *irn, ir_node *header_block) {
87 ir_node *block = get_nodes_block(irn);
89 return block_dominates(block, header_block);
93 * Do the replacement operation.
95 * @param irn the node that will be replaced
96 * @param iv the induction variable
97 * @param rc the region constant
98 * @param env the environment
100 static void replace(ir_node *irn, ir_node *iv, ir_node *rc, iv_env *env) {
101 DB((dbg, LEVEL_2, " Replacing %+F\n", irn));
105 * check if a node can be replaced
107 static void check_replace(ir_node *irn, iv_env *env) {
108 ir_node *left, *right, *iv, *rc;
109 ir_op *op = get_irn_op(irn);
110 opcode code = get_op_code(op);
119 left = get_binop_left(irn);
120 right = get_binop_right(irn);
122 liv = is_iv(left, env);
123 riv = is_iv(right, env);
124 if (liv && is_rc(right, liv->header)) {
125 iv = left; rc = right;
127 else if (is_op_commutative(op) &&
128 riv && is_rc(left, riv->header)) {
129 iv = right; rc = left;
133 replace(irn, iv, rc, env);
141 * check which SCC's are induction variables
143 static void classify_iv(scc *pscc, iv_env *env) {
144 ir_node *irn, *next, *header = NULL;
148 /* find the header block for this scc */
149 for (irn = pscc->head; irn; irn = next) {
150 node_entry *e = get_irn_link(irn);
151 ir_node *block = get_nodes_block(irn);
154 b = &env->entries[get_irn_idx(block)];
157 if (h->POnum < b->POnum) {
167 pscc->header = header;
169 for (irn = pscc->head; irn; irn = next) {
170 node_entry *e = get_irn_link(irn);
173 switch (get_irn_opcode(irn)) {
177 for (j = get_irn_arity(irn) - 1; j >= 0; --j) {
178 ir_node *pred = get_irn_n(irn, j);
179 node_entry *pe = &env->entries[get_irn_idx(pred)];
181 if (pe->pscc != e->pscc) {
182 /* not in the same SCC, must be a region const */
183 if (! is_rc(pred, header)) {
184 /* not an induction variable */
191 /* not an induction variable */
195 /* found an induction variable */
196 DB((dbg, LEVEL_2, " Found an induction variable in %+F\n", pscc->head));
201 for (irn = pscc->head; irn; irn = next) {
202 node_entry *e = get_irn_link(irn);
205 check_replace(irn, env);
210 * Do the replacement: We must do this as an additional step because
211 * of our loop-tree structure.
213 static void find_replacement(ir_loop *loop, iv_env *env) {
216 if (! IS_LOOP_IV(loop)) {
217 /* do replacements */
218 n = get_loop_n_nodes(loop);
219 for (i = 0; i < n; ++i) {
220 ir_node *irn = get_loop_node(loop, i);
221 ir_node *left, *right, *iv, *rc;
222 opcode code = get_irn_opcode(irn);
230 left = get_binop_left(irn);
231 right = get_binop_right(irn);
233 if (is_iv(left, env) && is_rc(right, left)) {
234 iv = left; rc = right;
236 else if (code != iro_Sub &&
237 is_iv(right, env) && is_rc(left, right)) {
238 iv = right; rc = left;
242 replace(irn, iv, rc, env);
249 n = get_loop_n_sons(loop);
250 for (i = 0; i < n; ++i) {
251 ir_loop *child = get_loop_son(loop, i);
252 find_replacement(child, env);
257 * Process a SCC given as a list.
259 static void process_scc(scc *pscc, iv_env *env) {
260 ir_node *head = pscc->head;
261 node_entry *e = get_irn_link(head);
269 DB((dbg, LEVEL_3, " SCC at %p:\n ", pscc));
270 for (irn = pscc->head; irn; irn = next) {
271 node_entry *e = get_irn_link(irn);
275 DB((dbg, LEVEL_3, " %+F,", irn));
277 DB((dbg, LEVEL_3, "\n"));
281 if (e->next == NULL) {
282 /* this SCC has only a single member */
283 check_replace(head, env);
286 classify_iv(pscc, env);
291 * Push a node onto the stack.
293 static void push(iv_env *env, ir_node *n) {
294 if (env->tos == ARR_LEN(env->stack)) {
295 int nlen = ARR_LEN(env->stack) * 2;
296 ARR_RESIZE(ir_node *, env->stack, nlen);
298 env->stack[env->tos++] = n;
299 env->entries[get_irn_idx(n)].in_stack = 1;
303 * pop a node from the stack
305 * @return The topmost node
307 static ir_node *pop(iv_env *env)
309 ir_node *n = env->stack[--env->tos];
310 env->entries[get_irn_idx(n)].in_stack = 0;
314 static void dfs(ir_node *irn, iv_env *env)
317 node_entry *node = &env->entries[get_irn_idx(irn)];
319 mark_irn_visited(irn);
321 /* do not put blocks into the scc */
323 n = get_irn_arity(irn);
324 for (i = 0; i < n; ++i) {
325 ir_node *pred = get_irn_n(irn, i);
327 if (irn_not_visited(pred))
332 ir_node *block = get_nodes_block(irn);
334 node->DFSnum = env->nextDFSnum++;
335 node->low = node->DFSnum;
338 /* handle the block */
339 if (irn_not_visited(block))
342 n = get_irn_arity(irn);
343 for (i = 0; i < n; ++i) {
344 ir_node *pred = get_irn_n(irn, i);
345 node_entry *o = &env->entries[get_irn_idx(pred)];
347 if (irn_not_visited(pred)) {
349 node->low = MIN(node->low, o->low);
351 if (o->DFSnum < node->DFSnum && o->in_stack)
352 node->low = MIN(o->DFSnum, node->low);
354 if (node->low == node->DFSnum) {
355 scc *pscc = obstack_alloc(&env->obst, sizeof(*pscc));
363 e = &env->entries[get_irn_idx(x)];
365 e->next = pscc->head;
368 /* link the node entry for easier access */
372 process_scc(pscc, env);
378 * Do the DFS by starting end the End node
380 static void do_dfs(ir_graph *irg, iv_env *env) {
381 ir_graph *rem = current_ir_graph;
382 ir_node *end = get_irg_end(irg);
385 current_ir_graph = irg;
386 inc_irg_visited(irg);
388 /* visit all visible nodes */
391 /* visit the keep-alives */
392 n = get_End_n_keepalives(end);
393 for (i = 0; i < n; ++i) {
394 ir_node *ka = get_End_keepalive(end, i);
396 if (irn_not_visited(ka))
399 current_ir_graph = rem;
403 * Post-block-walker: assign the post-order number.
405 static void assign_po(ir_node *block, void *ctx) {
407 int idx = get_irn_idx(block);
409 env->entries[idx].POnum = env->POnum++;
412 /* Performs Operator Strength Reduction for the passed graph. */
413 void opt_osr(ir_graph *irg) {
416 if (! get_opt_strength_red())
419 FIRM_DBG_REGISTER(dbg, "firm.opt.osr");
420 firm_dbg_set_mask(dbg, SET_LEVEL_2);
422 /* and dominance as well */
425 DB((dbg, LEVEL_1, "Doing Operator Strength Reduction for %+F\n", irg));
427 env.entries = NEW_ARR_F(node_entry, get_irg_last_idx(irg));
428 memset(env.entries, 0, get_irg_last_idx(irg));
430 obstack_init(&env.obst);
431 env.stack = NEW_ARR_F(ir_node *, 128);
437 /* calculate the post order number */
438 irg_block_walk_graph(irg, NULL, assign_po, &env);
443 set_irg_outs_inconsistent(irg);
444 set_irg_loopinfo_inconsistent(irg);
446 DB((dbg, LEVEL_1, "Replacements: %u\n\n", env.replaced));
448 DEL_ARR_F(env.stack);
449 obstack_free(&env.obst, NULL);
450 DEL_ARR_F(env.entries);