int flow_loops_find (struct loops *loops, int flags) { int i; int b; int num_loops; edge e; sbitmap headers; int *dfs_order; int *rc_order; basic_block header; basic_block bb; /* This function cannot be repeatedly called with different flags to build up the loop information. The loop tree must always be built if this function is called. */ if (! (flags & LOOP_TREE)) abort (); memset (loops, 0, sizeof *loops); /* Taking care of this degenerate case makes the rest of this code simpler. */ if (n_basic_blocks == 0) return 0; dfs_order = NULL; rc_order = NULL; /* Join loops with shared headers. */ canonicalize_loop_headers (); /* Compute the dominators. */ calculate_dominance_info (CDI_DOMINATORS); /* Count the number of loop headers. This should be the same as the number of natural loops. */ headers = sbitmap_alloc (last_basic_block); sbitmap_zero (headers); num_loops = 0; FOR_EACH_BB (header) { int more_latches = 0; header->loop_depth = 0; /* If we have an abnormal predecessor, do not consider the loop (not worth the problems). */ for (e = header->pred; e; e = e->pred_next) if (e->flags & EDGE_ABNORMAL) break; if (e) continue; for (e = header->pred; e; e = e->pred_next) { basic_block latch = e->src; if (e->flags & EDGE_ABNORMAL) abort (); /* Look for back edges where a predecessor is dominated by this block. A natural loop has a single entry node (header) that dominates all the nodes in the loop. It also has single back edge to the header from a latch node. */ if (latch != ENTRY_BLOCK_PTR && dominated_by_p (CDI_DOMINATORS, latch, header)) { /* Shared headers should be eliminated by now. */ if (more_latches) abort (); more_latches = 1; SET_BIT (headers, header->index); num_loops++; } } } /* Allocate loop structures. */ loops->parray = xcalloc (num_loops + 1, sizeof (struct loop *)); /* Dummy loop containing whole function. */ loops->parray[0] = xcalloc (1, sizeof (struct loop)); loops->parray[0]->next = NULL; loops->parray[0]->inner = NULL; loops->parray[0]->outer = NULL; loops->parray[0]->depth = 0; loops->parray[0]->pred = NULL; loops->parray[0]->num_nodes = n_basic_blocks + 2; loops->parray[0]->latch = EXIT_BLOCK_PTR; loops->parray[0]->header = ENTRY_BLOCK_PTR; ENTRY_BLOCK_PTR->loop_father = loops->parray[0]; EXIT_BLOCK_PTR->loop_father = loops->parray[0]; loops->tree_root = loops->parray[0]; /* Find and record information about all the natural loops in the CFG. */ loops->num = 1; FOR_EACH_BB (bb) bb->loop_father = loops->tree_root; if (num_loops) { /* Compute depth first search order of the CFG so that outer natural loops will be found before inner natural loops. */ dfs_order = xmalloc (n_basic_blocks * sizeof (int)); rc_order = xmalloc (n_basic_blocks * sizeof (int)); flow_depth_first_order_compute (dfs_order, rc_order); /* Save CFG derived information to avoid recomputing it. */ loops->cfg.dfs_order = dfs_order; loops->cfg.rc_order = rc_order; num_loops = 1; for (b = 0; b < n_basic_blocks; b++) { struct loop *loop; /* Search the nodes of the CFG in reverse completion order so that we can find outer loops first. */ if (!TEST_BIT (headers, rc_order[b])) continue; header = BASIC_BLOCK (rc_order[b]); loop = loops->parray[num_loops] = xcalloc (1, sizeof (struct loop)); loop->header = header; loop->num = num_loops; num_loops++; /* Look for the latch for this header block. */ for (e = header->pred; e; e = e->pred_next) { basic_block latch = e->src; if (latch != ENTRY_BLOCK_PTR && dominated_by_p (CDI_DOMINATORS, latch, header)) { loop->latch = latch; break; } } flow_loop_tree_node_add (header->loop_father, loop); loop->num_nodes = flow_loop_nodes_find (loop->header, loop); } /* Assign the loop nesting depth and enclosed loop level for each loop. */ loops->levels = flow_loops_level_compute (loops); /* Scan the loops. */ for (i = 1; i < num_loops; i++) flow_loop_scan (loops->parray[i], flags); loops->num = num_loops; } else { free_dominance_info (CDI_DOMINATORS); } sbitmap_free (headers); loops->state = 0; #ifdef ENABLE_CHECKING verify_flow_info (); verify_loop_structure (loops); #endif return loops->num; }
void linear_transform_loops (struct loops *loops) { unsigned int i; compute_immediate_uses (TDFA_USE_OPS | TDFA_USE_VOPS, NULL); for (i = 1; i < loops->num; i++) { unsigned int depth = 0; varray_type datarefs; varray_type dependence_relations; struct loop *loop_nest = loops->parray[i]; struct loop *temp; VEC (tree) *oldivs = NULL; VEC (tree) *invariants = NULL; lambda_loopnest before, after; lambda_trans_matrix trans; bool problem = false; bool need_perfect_nest = false; /* If it's not a loop nest, we don't want it. We also don't handle sibling loops properly, which are loops of the following form: for (i = 0; i < 50; i++) { for (j = 0; j < 50; j++) { ... } for (j = 0; j < 50; j++) { ... } } */ if (!loop_nest->inner) continue; depth = 1; for (temp = loop_nest->inner; temp; temp = temp->inner) { flow_loop_scan (temp, LOOP_ALL); /* If we have a sibling loop or multiple exit edges, jump ship. */ if (temp->next || temp->num_exits != 1) { problem = true; break; } depth ++; } if (problem) continue; /* Analyze data references and dependence relations using scev. */ VARRAY_GENERIC_PTR_INIT (datarefs, 10, "datarefs"); VARRAY_GENERIC_PTR_INIT (dependence_relations, 10, "dependence_relations"); compute_data_dependences_for_loop (depth, loop_nest, &datarefs, &dependence_relations); if (dump_file && (dump_flags & TDF_DETAILS)) { unsigned int j; for (j = 0; j < VARRAY_ACTIVE_SIZE (dependence_relations); j++) { struct data_dependence_relation *ddr = (struct data_dependence_relation *) VARRAY_GENERIC_PTR (dependence_relations, j); if (DDR_ARE_DEPENDENT (ddr) == NULL_TREE) { fprintf (dump_file, "DISTANCE_V ("); print_lambda_vector (dump_file, DDR_DIST_VECT (ddr), DDR_SIZE_VECT (ddr)); fprintf (dump_file, ")\n"); fprintf (dump_file, "DIRECTION_V ("); print_lambda_vector (dump_file, DDR_DIR_VECT (ddr), DDR_SIZE_VECT (ddr)); fprintf (dump_file, ")\n"); } } fprintf (dump_file, "\n\n"); } /* Build the transformation matrix. */ trans = lambda_trans_matrix_new (depth, depth); lambda_matrix_id (LTM_MATRIX (trans), depth); trans = try_interchange_loops (trans, depth, dependence_relations, datarefs, loop_nest); if (lambda_trans_matrix_id_p (trans)) { if (dump_file) fprintf (dump_file, "Won't transform loop. Optimal transform is the identity transform\n"); continue; } /* Check whether the transformation is legal. */ if (!lambda_transform_legal_p (trans, depth, dependence_relations)) { if (dump_file) fprintf (dump_file, "Can't transform loop, transform is illegal:\n"); continue; } if (!perfect_nest_p (loop_nest)) need_perfect_nest = true; before = gcc_loopnest_to_lambda_loopnest (loops, loop_nest, &oldivs, &invariants, need_perfect_nest); if (!before) continue; if (dump_file) { fprintf (dump_file, "Before:\n"); print_lambda_loopnest (dump_file, before, 'i'); } after = lambda_loopnest_transform (before, trans); if (dump_file) { fprintf (dump_file, "After:\n"); print_lambda_loopnest (dump_file, after, 'u'); } lambda_loopnest_to_gcc_loopnest (loop_nest, oldivs, invariants, after, trans); if (dump_file) fprintf (dump_file, "Successfully transformed loop.\n"); oldivs = NULL; invariants = NULL; free_dependence_relations (dependence_relations); free_data_refs (datarefs); } free_df (); scev_reset (); rewrite_into_loop_closed_ssa (); #ifdef ENABLE_CHECKING verify_loop_closed_ssa (); #endif }