static void create_canonical_iv (struct loop *loop, edge exit, tree niter) { edge in; tree cond, type, var; block_stmt_iterator incr_at; enum tree_code cmp; if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Added canonical iv to loop %d, ", loop->num); print_generic_expr (dump_file, niter, TDF_SLIM); fprintf (dump_file, " iterations.\n"); } cond = last_stmt (exit->src); in = EDGE_SUCC (exit->src, 0); if (in == exit) in = EDGE_SUCC (exit->src, 1); /* Note that we do not need to worry about overflows, since type of niter is always unsigned and all comparisons are just for equality/nonequality -- i.e. everything works with a modulo arithmetics. */ type = TREE_TYPE (niter); niter = fold_build2 (PLUS_EXPR, type, niter, build_int_cst (type, 1)); incr_at = bsi_last (in->src); create_iv (niter, fold_convert (type, integer_minus_one_node), NULL_TREE, loop, &incr_at, false, NULL, &var); cmp = (exit->flags & EDGE_TRUE_VALUE) ? EQ_EXPR : NE_EXPR; COND_EXPR_COND (cond) = build2 (cmp, boolean_type_node, var, build_int_cst (type, 0)); update_stmt (cond); }
bool potentially_threadable_block (basic_block bb) { block_stmt_iterator bsi; /* If BB has a single successor or a single predecessor, then there is no threading opportunity. */ if (single_succ_p (bb) || single_pred_p (bb)) return false; /* If BB does not end with a conditional, switch or computed goto, then there is no threading opportunity. */ bsi = bsi_last (bb); if (bsi_end_p (bsi) || ! bsi_stmt (bsi) || (TREE_CODE (bsi_stmt (bsi)) != COND_EXPR && TREE_CODE (bsi_stmt (bsi)) != GOTO_EXPR && TREE_CODE (bsi_stmt (bsi)) != SWITCH_EXPR)) return false; return true; }
void walk_dominator_tree (struct dom_walk_data *walk_data, basic_block bb) { void *bd = NULL; basic_block dest; block_stmt_iterator bsi; bool is_interesting; basic_block *worklist = XNEWVEC (basic_block, n_basic_blocks * 2); int sp = 0; while (true) { /* Don't worry about unreachable blocks. */ if (EDGE_COUNT (bb->preds) > 0 || bb == ENTRY_BLOCK_PTR || bb == EXIT_BLOCK_PTR) { /* If block BB is not interesting to the caller, then none of the callbacks that walk the statements in BB are going to be executed. */ is_interesting = walk_data->interesting_blocks == NULL || TEST_BIT (walk_data->interesting_blocks, bb->index); /* Callback to initialize the local data structure. */ if (walk_data->initialize_block_local_data) { bool recycled; /* First get some local data, reusing any local data pointer we may have saved. */ if (VEC_length (void_p, walk_data->free_block_data) > 0) { bd = VEC_pop (void_p, walk_data->free_block_data); recycled = 1; } else { bd = xcalloc (1, walk_data->block_local_data_size); recycled = 0; } /* Push the local data into the local data stack. */ VEC_safe_push (void_p, heap, walk_data->block_data_stack, bd); /* Call the initializer. */ walk_data->initialize_block_local_data (walk_data, bb, recycled); } /* Callback for operations to execute before we have walked the dominator children, but before we walk statements. */ if (walk_data->before_dom_children_before_stmts) (*walk_data->before_dom_children_before_stmts) (walk_data, bb); /* Statement walk before walking dominator children. */ if (is_interesting && walk_data->before_dom_children_walk_stmts) { if (walk_data->walk_stmts_backward) for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi)) (*walk_data->before_dom_children_walk_stmts) (walk_data, bb, bsi); else for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) (*walk_data->before_dom_children_walk_stmts) (walk_data, bb, bsi); } /* Callback for operations to execute before we have walked the dominator children, and after we walk statements. */ if (walk_data->before_dom_children_after_stmts) (*walk_data->before_dom_children_after_stmts) (walk_data, bb); /* Mark the current BB to be popped out of the recursion stack once childs are processed. */ worklist[sp++] = bb; worklist[sp++] = NULL; for (dest = first_dom_son (walk_data->dom_direction, bb); dest; dest = next_dom_son (walk_data->dom_direction, dest)) worklist[sp++] = dest; } /* NULL is used to signalize pop operation in recursion stack. */ while (sp > 0 && !worklist[sp - 1]) { --sp; bb = worklist[--sp]; is_interesting = walk_data->interesting_blocks == NULL || TEST_BIT (walk_data->interesting_blocks, bb->index); /* Callback for operations to execute after we have walked the dominator children, but before we walk statements. */ if (walk_data->after_dom_children_before_stmts) (*walk_data->after_dom_children_before_stmts) (walk_data, bb); /* Statement walk after walking dominator children. */ if (is_interesting && walk_data->after_dom_children_walk_stmts) { if (walk_data->walk_stmts_backward) for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi)) (*walk_data->after_dom_children_walk_stmts) (walk_data, bb, bsi); else for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) (*walk_data->after_dom_children_walk_stmts) (walk_data, bb, bsi); } /* Callback for operations to execute after we have walked the dominator children and after we have walked statements. */ if (walk_data->after_dom_children_after_stmts) (*walk_data->after_dom_children_after_stmts) (walk_data, bb); if (walk_data->initialize_block_local_data) { /* And finally pop the record off the block local data stack. */ bd = VEC_pop (void_p, walk_data->block_data_stack); /* And save the block data so that we can re-use it. */ VEC_safe_push (void_p, heap, walk_data->free_block_data, bd); } } if (sp) bb = worklist[--sp]; else break; } free (worklist); }
static void mf_build_check_statement_for (tree base, tree limit, block_stmt_iterator *instr_bsi, location_t *locus, tree dirflag) { tree_stmt_iterator head, tsi; block_stmt_iterator bsi; basic_block cond_bb, then_bb, join_bb; edge e; tree cond, t, u, v; tree mf_base; tree mf_elem; tree mf_limit; /* We first need to split the current basic block, and start altering the CFG. This allows us to insert the statements we're about to construct into the right basic blocks. */ cond_bb = bb_for_stmt (bsi_stmt (*instr_bsi)); bsi = *instr_bsi; bsi_prev (&bsi); if (! bsi_end_p (bsi)) e = split_block (cond_bb, bsi_stmt (bsi)); else e = split_block_after_labels (cond_bb); cond_bb = e->src; join_bb = e->dest; /* A recap at this point: join_bb is the basic block at whose head is the gimple statement for which this check expression is being built. cond_bb is the (possibly new, synthetic) basic block the end of which will contain the cache-lookup code, and a conditional that jumps to the cache-miss code or, much more likely, over to join_bb. */ /* Create the bb that contains the cache-miss fallback block (mf_check). */ then_bb = create_empty_bb (cond_bb); make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE); make_single_succ_edge (then_bb, join_bb, EDGE_FALLTHRU); /* Mark the pseudo-fallthrough edge from cond_bb to join_bb. */ e = find_edge (cond_bb, join_bb); e->flags = EDGE_FALSE_VALUE; e->count = cond_bb->count; e->probability = REG_BR_PROB_BASE; /* Update dominance info. Note that bb_join's data was updated by split_block. */ if (dom_info_available_p (CDI_DOMINATORS)) { set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb); set_immediate_dominator (CDI_DOMINATORS, join_bb, cond_bb); } /* Build our local variables. */ mf_elem = create_tmp_var (mf_cache_structptr_type, "__mf_elem"); mf_base = create_tmp_var (mf_uintptr_type, "__mf_base"); mf_limit = create_tmp_var (mf_uintptr_type, "__mf_limit"); /* Build: __mf_base = (uintptr_t) <base address expression>. */ t = build2 (MODIFY_EXPR, void_type_node, mf_base, convert (mf_uintptr_type, unshare_expr (base))); SET_EXPR_LOCUS (t, locus); gimplify_to_stmt_list (&t); head = tsi_start (t); tsi = tsi_last (t); /* Build: __mf_limit = (uintptr_t) <limit address expression>. */ t = build2 (MODIFY_EXPR, void_type_node, mf_limit, convert (mf_uintptr_type, unshare_expr (limit))); SET_EXPR_LOCUS (t, locus); gimplify_to_stmt_list (&t); tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); /* Build: __mf_elem = &__mf_lookup_cache [(__mf_base >> __mf_shift) & __mf_mask]. */ t = build2 (RSHIFT_EXPR, mf_uintptr_type, mf_base, (flag_mudflap_threads ? mf_cache_shift_decl : mf_cache_shift_decl_l)); t = build2 (BIT_AND_EXPR, mf_uintptr_type, t, (flag_mudflap_threads ? mf_cache_mask_decl : mf_cache_mask_decl_l)); t = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (mf_cache_array_decl)), mf_cache_array_decl, t, NULL_TREE, NULL_TREE); t = build1 (ADDR_EXPR, mf_cache_structptr_type, t); t = build2 (MODIFY_EXPR, void_type_node, mf_elem, t); SET_EXPR_LOCUS (t, locus); gimplify_to_stmt_list (&t); tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); /* Quick validity check. if (__mf_elem->low > __mf_base || (__mf_elem_high < __mf_limit)) { __mf_check (); ... and only if single-threaded: __mf_lookup_shift_1 = f...; __mf_lookup_mask_l = ...; } It is expected that this body of code is rarely executed so we mark the edge to the THEN clause of the conditional jump as unlikely. */ /* Construct t <-- '__mf_elem->low > __mf_base'. */ t = build3 (COMPONENT_REF, mf_uintptr_type, build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem), TYPE_FIELDS (mf_cache_struct_type), NULL_TREE); t = build2 (GT_EXPR, boolean_type_node, t, mf_base); /* Construct '__mf_elem->high < __mf_limit'. First build: 1) u <-- '__mf_elem->high' 2) v <-- '__mf_limit'. Then build 'u <-- (u < v). */ u = build3 (COMPONENT_REF, mf_uintptr_type, build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem), TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type)), NULL_TREE); v = mf_limit; u = build2 (LT_EXPR, boolean_type_node, u, v); /* Build the composed conditional: t <-- 't || u'. Then store the result of the evaluation of 't' in a temporary variable which we can use as the condition for the conditional jump. */ t = build2 (TRUTH_OR_EXPR, boolean_type_node, t, u); cond = create_tmp_var (boolean_type_node, "__mf_unlikely_cond"); t = build2 (MODIFY_EXPR, boolean_type_node, cond, t); gimplify_to_stmt_list (&t); tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); /* Build the conditional jump. 'cond' is just a temporary so we can simply build a void COND_EXPR. We do need labels in both arms though. */ t = build3 (COND_EXPR, void_type_node, cond, build1 (GOTO_EXPR, void_type_node, tree_block_label (then_bb)), build1 (GOTO_EXPR, void_type_node, tree_block_label (join_bb))); SET_EXPR_LOCUS (t, locus); tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); /* At this point, after so much hard work, we have only constructed the conditional jump, if (__mf_elem->low > __mf_base || (__mf_elem_high < __mf_limit)) The lowered GIMPLE tree representing this code is in the statement list starting at 'head'. We can insert this now in the current basic block, i.e. the one that the statement we're instrumenting was originally in. */ bsi = bsi_last (cond_bb); for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi)) bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING); /* Now build up the body of the cache-miss handling: __mf_check(); refresh *_l vars. This is the body of the conditional. */ u = tree_cons (NULL_TREE, mf_file_function_line_tree (locus == NULL ? UNKNOWN_LOCATION : *locus), NULL_TREE); u = tree_cons (NULL_TREE, dirflag, u); /* NB: we pass the overall [base..limit] range to mf_check. */ u = tree_cons (NULL_TREE, fold_build2 (PLUS_EXPR, integer_type_node, fold_build2 (MINUS_EXPR, mf_uintptr_type, mf_limit, mf_base), integer_one_node), u); u = tree_cons (NULL_TREE, mf_base, u); t = build_function_call_expr (mf_check_fndecl, u); gimplify_to_stmt_list (&t); head = tsi_start (t); tsi = tsi_last (t); if (! flag_mudflap_threads) { t = build2 (MODIFY_EXPR, void_type_node, mf_cache_shift_decl_l, mf_cache_shift_decl); tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); t = build2 (MODIFY_EXPR, void_type_node, mf_cache_mask_decl_l, mf_cache_mask_decl); tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); } /* Insert the check code in the THEN block. */ bsi = bsi_start (then_bb); for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi)) bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING); *instr_bsi = bsi_start (join_bb); bsi_next (instr_bsi); }