void Ltahoe_estimate_liveness (L_Func *fn, char *str) { L_Cb *cb; L_Oper *op; L_Attr *attr; int liveness, oplive; L_do_flow_analysis (fn, LIVE_VARIABLE); for (cb = fn->first_cb; cb; cb = cb->next_cb) { liveness = Set_size (L_get_cb_IN_set (cb)); for (op = cb->first_op; op; op = op->next_op) { oplive = Set_size (L_get_oper_IN_set (op)); if (oplive > liveness) liveness = oplive; } attr = L_new_attr (str, 1); L_set_int_attr_field (attr, 0, liveness); cb->attr = L_concat_attr (cb->attr, attr); } return; }
int L_loadstore_union_postdominates_amb (L_Func * fn, L_Cb * cb, L_Oper * oper, Set LDST, Set AMB) { int i, size; int *buf; L_Cb *def_cb; Set pd_cbset; int val = 0; pd_cbset = NULL; /* Convert RDEF is a set of cbs */ size = Set_size (LDST); if (!size) return 0; buf = (int *) Lcode_malloc (sizeof (int) * size); Set_2array (LDST, buf); for (i = 0; i < size; i++) { def_cb = L_oper_hash_tbl_find_cb (L_fn->oper_hash_tbl, buf[i]); pd_cbset = Set_add (pd_cbset, def_cb->id); } Lcode_free (buf); /* Foreach cb in AMB, Does pd_cbset post_dominate it */ size = Set_size (AMB); if (!size) return 1; buf = (int *) Lcode_malloc (sizeof (int) * size); Set_2array (AMB, buf); for (i = 0; i < size; i++) { def_cb = L_oper_hash_tbl_find_cb (L_fn->oper_hash_tbl, buf[i]); val = L_cb_set_dominates (fn, def_cb, cb, pd_cbset); if (!val) break; } Lcode_free (buf); pd_cbset = Set_dispose (pd_cbset); return val; }
int L_load_postdominates_each_store (L_Func * fn, L_Cb * cb, L_Oper * oper, Set RDEF) { int i, size; int *buf; L_Cb *use_cb; size = Set_size (RDEF); if (!size) return 0; buf = (int *) Lcode_malloc (sizeof (int) * size); Set_2array (RDEF, buf); for (i = 0; i < size; i++) { use_cb = L_oper_hash_tbl_find_cb (L_fn->oper_hash_tbl, buf[i]); if (!(L_in_cb_PDOM_set (use_cb, cb->id))) return 0; } Lcode_free (buf); return 1; }
static int LB_functionally_equivalent_cbs (Set cb_set) { L_Cb *cb1, *cb2; int num_cb, *cb_array, i, equiv; num_cb = Set_size (cb_set); if (num_cb <= 1) return (1); cb_array = (int *) Lcode_malloc (sizeof (int) * num_cb); Set_2array (cb_set, cb_array); if (!(cb1 = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, cb_array[0]))) L_punt ("LB_functionally_equivalent_cbs: corrupt cb_set"); equiv = 1; for (i = 1; i < num_cb; i++) { if (!(cb2 = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, cb_array[i]))) L_punt ("LB_functionally_equivalent_cbs: corrupt cb_set"); if (!LB_are_equivalent_cbs (cb1, cb2)) { equiv = 0; break; } } Lcode_free (cb_array); return (equiv); }
int L_store_union_dominates_load (L_Func * fn, L_Cb * cb, L_Oper * oper, Set RDEF) { int i, size; int *buf; L_Cb *def_cb, *start; Set cbset; int val; cbset = NULL; /* start needs to dominate all nodes in function */ start = fn->first_cb; /* Convert RDEF is a set of cbs */ size = Set_size (RDEF); if (!size) return 0; buf = (int *) Lcode_malloc (sizeof (int) * size); Set_2array (RDEF, buf); for (i = 0; i < size; i++) { def_cb = L_oper_hash_tbl_find_cb (L_fn->oper_hash_tbl, buf[i]); cbset = Set_add (cbset, def_cb->id); } Lcode_free (buf); /* Does cbset dominate cb from start */ val = L_cb_set_dominates (fn, start, cb, cbset); cbset = Set_dispose (cbset); return val; }
int L_load_compatible_each_load (L_Func * fn, L_Oper * oper, Set RDEF) { int i, size; int *buf; L_Oper *use_op; size = Set_size (RDEF); if (!size) return 0; buf = (int *) Lcode_malloc (sizeof (int) * size); Set_2array (RDEF, buf); for (i = 0; i < size; i++) { use_op = L_oper_hash_tbl_find_oper (fn->oper_hash_tbl, buf[i]); if (!L_same_opcode (oper, use_op)) return 0; } Lcode_free (buf); return 1; }
static int M_does_operand_contain_label_addr (L_Oper * oper, L_Operand * operand, int *reaching_df_done) { L_Oper *def_oper; Set def_set; int num_defs, *def_buf; int i, value = FALSE; if (!L_is_macro (operand)) { def_set = L_get_reaching_defs (operand, oper, reaching_df_done); if (def_set) { value = TRUE; num_defs = Set_size (def_set); def_buf = (int *) Lcode_malloc (sizeof (int) * (num_defs + 1)); (void) Set_2array (def_set, def_buf); for (i = 0; i < num_defs; i++) { def_oper = L_oper_hash_tbl_find_oper (L_fn->oper_hash_tbl, def_buf[i]); if (def_oper->proc_opc != TAHOEop_MOVL) { value = FALSE; break; } /* if */ } /* for i */ Lcode_free (def_buf); } /* if */ } /* if */ return (value); } /* M_does_operand_contain_label_addr */
void PSS_PrintLoops(PC_Loop pcloop) { int *bbs; int bb_count, i; for (; pcloop; pcloop = pcloop->sibling) { fprintf(debug_file_id, "-"); PSS_PrintLoops(pcloop->child); fprintf(debug_file_id, "Loop %d: ", pcloop->ID); bbs = (int *) calloc (Set_size (pcloop->body), sizeof (int)); bb_count = Set_2array (pcloop->body, bbs); for (i = 0; i < bb_count; i++) fprintf(debug_file_id, "%d ", bbs[i]); fprintf(debug_file_id, "\n"); free(bbs); } }
void LB_elim_all_loop_backedges (L_Func * fn) { int loop_count; L_Loop *loop; Set loop_done; /* count how many loops there are */ loop_count = 0; for (loop = fn->first_loop; loop; loop = loop->next_loop) loop_count++; /* inner most to outer */ loop_done = NULL; while (Set_size (loop_done) < loop_count) { for (loop = fn->first_loop; loop; loop = loop->next_loop) { if (Set_in (loop_done, loop->id)) continue; if (!Set_subtract_empty (loop->nested_loops, loop_done)) continue; loop_done = Set_add (loop_done, loop->id); LB_elim_loop_backedges (fn, loop); } } Set_dispose (loop_done); }
int LB_hb_jsr_in_cb_set (Set cb_set) { int i, num_jsr, num_cb, *cb_array; L_Cb *cb; L_Oper *oper; num_cb = Set_size (cb_set); if (num_cb <= 0) return (0); cb_array = (int *) alloca (sizeof (int) * num_cb); Set_2array (cb_set, cb_array); num_jsr = 0; for (i = 0; i < num_cb; i++) { if (!(cb = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, cb_array[i]))) L_punt ("LB_hb_jsr_in_cb_set: corrupt cb_set"); for (oper = cb->first_op; oper != NULL; oper = oper->next_op) if (L_subroutine_call_opcode (oper)) num_jsr++; } return (num_jsr > 0); }
int main(int argc, char* argv[]) { Set s = Set_new(); int a = 42; char* b = "hello"; assert(Set_size(s) == 0); Set_show(s, stdout, &show_func); Set_add(s, &a); assert(Set_size(s) == 1); Set_show(s, stdout, &show_func); Set_add(s, b); assert(Set_size(s) == 2); Set_show(s, stdout, &show_func); Set_remove(s, b); assert(Set_size(s) == 1); Set_show(s, stdout, &show_func); Set_remove(s, b); assert(Set_size(s) == 1); Set_show(s, stdout, &show_func); fprintf(stdout, "All tests passed!\n"); }
static void LB_combine_equivalent_backedges (L_Loop * loop) { int num_back_edge, *back_edge_array, i; L_Cb *cb, *keep_cb, *src_cb; L_Flow *src_flow, *next_flow; num_back_edge = Set_size (loop->back_edge_cb); if (num_back_edge <= 1) return; back_edge_array = (int *) alloca (sizeof (int) * num_back_edge); Set_2array (loop->back_edge_cb, back_edge_array); /* pick the one with the largest weight to keep */ if (!(keep_cb = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, back_edge_array[0]))) L_punt ("LB_combine_equivalent_backedges: corrupt backedge cbs"); for (i = 1; i < num_back_edge; i++) { if (!(cb = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, back_edge_array[i]))) L_punt ("LB_combine_equivalent_backedges: corrupt backedge cbs"); if (cb->weight > keep_cb->weight) keep_cb = cb; } #ifdef DEBUG fprintf (stderr, "keeping cb %d for equivalent Backedge combining\n", keep_cb->id); #endif for (i = 0; i < num_back_edge; i++) { cb = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, back_edge_array[i]); if (cb == keep_cb) continue; for (src_flow = cb->src_flow; src_flow; src_flow = next_flow) { next_flow = src_flow->next_flow; src_cb = src_flow->src_cb; LB_reconnect_blocks (src_cb, cb, keep_cb); } } L_rebuild_src_flow (L_fn); return; }
/* * LB_hb_region_contains_cycle * ---------------------------------------------------------------------- * Given a set of CB ids and a header CB, return 1 iff the region * contains a cycle which does not include the header; 0 otherwise. */ int LB_hb_region_contains_cycle (Set blocks, L_Cb * header) { int i, num_cb, *buf, cycle = 0; L_Cb *cb; num_cb = Set_size (blocks); buf = (int *) alloca (sizeof (int) * num_cb); Set_2array (blocks, buf); for (i = 0; i < num_cb; i++) { cb = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, buf[i]); cb->flags = L_CLR_BIT_FLAG (cb->flags, L_CB_VISITED); cb->flags = L_CLR_BIT_FLAG (cb->flags, L_CB_VISITED2); } if (dfs_visit (header, blocks, header)) { cycle = 1; } else { for (i = 0; i < num_cb; i++) { cb = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, buf[i]); if (L_EXTRACT_BIT_VAL (cb->flags, L_CB_VISITED)) continue; if (dfs_visit (cb, blocks, header)) { cycle = 1; break; } } } #ifdef DEBUG_CYCLE if (cycle) fprintf (stderr, "cycle in region (header %d)\n", header->id); #endif return cycle; }
/* \brief determine if an expr is part of a loop * * This will search for a given expression in a loop. This function * hsa two possible techniques of searching. If the expression has * a expr->BB hash table entry for the cfg, then we will find the inner * loop associated with that BB, and simply search up the loop tree for * the pcloop that is passed to this function. If the expression does * not have an expr->BB hash table entry, we will have to use the slower * algorithm that searches through all the expressions in all the BBs of * the loop. * * \param cfg * current cfg * \param lp * loop context to search in * \param find_expr * expression we are searching for * * \return * 1 if found, 0 if not */ int PC_LoopContainsExpr (PC_Graph cfg, PC_Loop lp, Expr find_expr) { PC_Block bb; if ((bb = PC_FindExprBB(cfg, find_expr->id))) { /* EXPR -> BB Hash worked! O(loopnest) algo... */ PC_Loop check_loop = bb->loop; if (check_loop == NULL) return 0; do { if (check_loop == lp) return 1; } while ((check_loop = check_loop->parent)); return 0; } else /* doh...we have to do it the slow way */ { int *bb_ids; int bb_ids_size, i; /* loop through the bb's in the loop */ bb_ids = (int *) calloc (Set_size (lp->body), sizeof (int)); bb_ids_size = Set_2array (lp->body, bb_ids); for (i = 0; i < bb_ids_size; i++) { Expr expr; _PC_ExprIter ei; bb = PC_FindBlock (cfg, bb_ids[i]); for (expr = PC_ExprIterFirst(bb, &ei, 1); expr; expr = PC_ExprIterNext(&ei, 1)) { if (find_expr == expr) return 1; } } /* for all bb's in lp */ /* not found... */ return 0; } }
static void PC_SetBlockSetLoop (PC_Graph cfg, PC_Loop lp, Set inner) { int cnt, i, *buf; PC_Block blk; if (!(cnt = Set_size (inner))) return; buf = alloca (cnt * sizeof (int)); Set_2array (inner, buf); for (i = 0; i < cnt; i++) { blk = PC_FindBlock (cfg, buf[i]); blk->loop = lp; } return; }
/* TARGAN ALGO FUNCTIONS */ static PSS_TarLoop Initialize_Tarjan (PC_Loop pcloop) { PSS_TarLoop tloop; int *bb_ids; int bb_ids_size, i; /* create the control structure */ tloop = New_TarLoop(pcloop); /* loop through the ops in the loop and generate * tarnodes for each of them */ bb_ids = (int *) calloc (Set_size (pcloop->body), sizeof (int)); bb_ids_size = Set_2array (pcloop->body, bb_ids); for (i = 0; i < bb_ids_size; i++) { PC_Block bb; Expr expr; _PC_ExprIter ei; bb = PC_FindBlock (cfg, bb_ids[i]); for (expr = PC_ExprIterFirst(bb, &ei, 1); expr; expr = PC_ExprIterNext(&ei, 1)) { /* we only care about assign ops, cause that is where * the action is */ #if 1 if (expr->opcode == OP_assign && expr->operands->opcode == OP_var) #else /* need to filter out meaningless phi nodes */ if (expr->opcode == OP_assign && expr->operands->opcode == OP_var && (expr->operands->sibling->opcode != OP_phi || expr->operands->value.var.ssa->uses)) #endif { New_TarNode(tloop, expr); } /* if assign op */ } /* for expr in bb */ } /* for bb's in loop */ return tloop; }
void LB_hb_mark_all_cbs_with_attr (Set cb_set, L_Attr * attr) { int i, num_cb, *cb_array; L_Attr *new_attr; L_Cb *cb; if (!(num_cb = Set_size (cb_set))) return; cb_array = (int *) alloca (sizeof (int) * num_cb); Set_2array (cb_set, cb_array); for (i = 0; i < num_cb; i++) { if (!(cb = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, cb_array[i]))) L_punt ("LB_hb_mark_all_cbs_with_attr: corrupt cb_set"); if (!L_find_attr (cb->attr, attr->name)) { new_attr = L_copy_attr (attr); cb->attr = L_concat_attr (cb->attr, new_attr); } } return; }
void L_loop_carried_dep_reduction (L_Loop *loop) { /* 10/25/04 REK Commenting out unused variables to quiet compiler warnings. */ #if 0 int change, j, same_cb; L_Sync_Info *sync_info; #endif int i, num_cb, *loop_cb = NULL, num_backedge_cb, *backedge_cb = NULL, num_out_cb, *out_cb = NULL, increment = 0; L_Cb *cb, *last_cb; L_Oper *ind_op, *oper, *oper2, *last_use; L_Operand *temp, *inductor_reg, *ind_offset; /* setup cb array */ num_cb = Set_size (loop->loop_cb); if (num_cb > 0) { loop_cb = (int *) Lcode_malloc (sizeof (int) * num_cb); Set_2array (loop->loop_cb, loop_cb); } /* setup backedge_cb array */ num_backedge_cb = Set_size (loop->back_edge_cb); if (num_backedge_cb > 0) { backedge_cb = (int *) Lcode_malloc (sizeof (int) * num_backedge_cb); Set_2array (loop->back_edge_cb, backedge_cb); } /* setup out_cb array */ num_out_cb = Set_size (loop->out_cb); if (num_out_cb > 0) { out_cb = (int *) Lcode_malloc (sizeof (int) * num_out_cb); Set_2array (loop->out_cb, out_cb); } L_find_all_ind_info (loop, loop_cb, num_cb); for (i = 0; i < num_cb; i++) { cb = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, loop_cb[i]); for (ind_op = cb->first_op; ind_op != NULL; ind_op = ind_op->next_op) { /* * match pattern */ if (!(Set_in (loop->basic_ind_var_op, ind_op->id))) continue; if (!(L_int_add_opcode (ind_op) || L_int_sub_opcode (ind_op))) continue; last_use = L_find_last_use_of_ind_var (loop, loop_cb, num_cb, backedge_cb, num_backedge_cb, cb, ind_op); if (!(L_load_opcode (last_use) || L_store_opcode (last_use))) continue; if (L_marked_as_post_increment (last_use) || L_marked_as_pre_increment (last_use)) continue; /* if increment is sub, convert it to an add */ if (L_int_sub_opcode (ind_op) && L_is_int_constant (ind_op->src[1])) { temp = ind_op->src[1]; ind_op->src[1] = L_new_gen_int_operand (-(temp->value.i)); L_delete_operand (temp); L_change_opcode (ind_op, L_corresponding_add (ind_op)); } inductor_reg = ind_op->dest[0]; /* Determine the increment of the inductor */ if (L_same_operand (inductor_reg, ind_op->src[0])) increment = ind_op->src[1]->value.i; else if (L_same_operand (inductor_reg, ind_op->src[1])) increment = ind_op->src[0]->value.i; else L_punt ("assumption violated"); last_cb = L_oper_hash_tbl_find_cb (L_fn->oper_hash_tbl, last_use->id); for (oper = last_cb->first_op; oper && (oper != last_use); oper = oper->next_op) { if (!(L_load_opcode (oper) || L_store_opcode (oper))) continue; if (L_same_operand (inductor_reg, oper->src[0])) ind_offset = oper->src[1]; else if (L_same_operand (inductor_reg, oper->src[1])) ind_offset = oper->src[0]; else continue; if (L_is_int_constant (ind_offset)) { if (ind_offset != oper->src[1]) L_punt ("constant in src[0]"); /* Look for any corresponding load/store from same inductor within increment */ for (oper2 = oper->next_op; oper2 && (oper2 != ind_op); oper2 = oper2->next_op) { if (!(L_load_opcode (oper2) || L_store_opcode (oper2))) continue; if (!(L_same_operand (oper2->src[0], inductor_reg) && L_is_int_constant (oper2->src[1]))) continue; if ((increment > 0) && (oper2->src[1]->value.i >= (ind_offset->value.i + increment))) continue; if ((increment < 0) && (oper2->src[1]->value.i <= (ind_offset->value.i + increment))) continue; L_clear_inner_carried_flag (oper, oper2); } } else { /* Look for any corresponding load/store with exact same operands */ for (oper2 = oper->next_op; oper2 && (oper2 != ind_op); oper2 = oper2->next_op) { if (!(L_load_opcode (oper2) || L_store_opcode (oper2))) continue; if (!(L_same_operand (oper->src[0], oper2->src[0]) && L_same_operand (oper->src[1], oper2->src[1]))) continue; L_clear_inner_carried_flag (oper, oper2); } } } } } if (loop_cb != NULL) Lcode_free (loop_cb); if (backedge_cb != NULL) Lcode_free (backedge_cb); if (out_cb != NULL) Lcode_free (out_cb); }
static int O_spill_fill_around_sync (L_Func * fn, L_Cb * cb, L_Oper * op, int *int_spill_start, int *int_spill_end) { L_Oper *op_list; L_Operand *spill_reg; Set live_variables; Set live_regs; int *live_reg_ids; int num_live_regs; Set live_macros; int *live_macro_ids; int num_live_macros; int variable; int int_offset, fp_offset; int_offset = *int_spill_start; fp_offset = fn->s_local; live_variables = L_get_oper_IN_set (op); /* registers */ live_regs = L_unmap_reg_set (live_variables); num_live_regs = Set_size (live_regs); live_reg_ids = calloc (num_live_regs, sizeof (int)); Set_2array (live_regs, live_reg_ids); /* macros */ live_macros = L_unmap_macro_set (live_variables); num_live_macros = Set_size (live_macros); live_macro_ids = calloc (num_live_macros, sizeof (int)); Set_2array (live_macros, live_macro_ids); #ifdef DEBUG # ifdef DEBUG1 L_print_cb (stderr, fn, cb); Set_print (stderr, "Live OUT set", live_variables); Set_print (stderr, "Registers", live_regs); Set_print (stderr, "Macros", live_macros); # endif fprintf (stderr, "fp setjmp spill/fill ops: "); #endif /* * Spill the floating point registers and macros into * newly-allocated local variable space */ /* first spill the floating point registers */ /* create an operand, the id of it will be altered later. */ spill_reg = L_new_register_operand (0, L_CTYPE_DOUBLE, L_PTYPE_NULL); for (variable = 0; variable < num_live_regs; variable++) { if (IS_FP_REGISTER (live_reg_ids[variable])) { spill_reg->value.r = live_reg_ids[variable]; op_list = O_spill_reg (live_reg_ids[variable], L_OPERAND_REGISTER, spill_reg, fp_offset, NULL, R_JSR_SAVE_CODE); O_insert_spill_sequence (cb, op, op_list); op_list = O_fill_reg (live_reg_ids[variable], L_OPERAND_REGISTER, spill_reg, fp_offset, NULL, R_JSR_SAVE_CODE); O_insert_fill_sequence (cb, op, op_list); fp_offset += 16; } } #ifdef DEBUG fprintf (stderr, "\n"); fprintf (stderr, "fp macro setjmp spill/fill ops: "); #endif /* spill the floating point macros */ /* change the operand to a macro operand. */ L_assign_type_float_macro (spill_reg); for (variable = 0; variable < num_live_macros; variable++) { if (IS_FP_MACRO_TO_SPILL (live_macro_ids[variable])) { spill_reg->value.r = live_macro_ids[variable]; op_list = O_spill_reg (live_macro_ids[variable], L_OPERAND_MACRO, spill_reg, fp_offset, NULL, R_JSR_SAVE_CODE); O_insert_spill_sequence (cb, op, op_list); op_list = O_fill_reg (live_macro_ids[variable], L_OPERAND_MACRO, spill_reg, fp_offset, NULL, R_JSR_SAVE_CODE); O_insert_fill_sequence (cb, op, op_list); fp_offset += 16; } } #ifdef DEBUG fprintf (stderr, "\n"); fprintf (stderr, "int setjmp spill/fill ops: "); #endif /* * Spill the integer registers and macros into sync space */ L_assign_type_int_register (spill_reg); for (variable = 0; variable < num_live_regs; variable++) { if (IS_INT_REGISTER (live_reg_ids[variable])) { int_offset += 8; spill_reg->value.r = live_reg_ids[variable]; op_list = O_spill_reg (live_reg_ids[variable], L_OPERAND_REGISTER, spill_reg, -int_offset, NULL, R_JSR_SAVE_CODE); O_insert_spill_sequence (cb, op, op_list); op_list = O_fill_reg (live_reg_ids[variable], L_OPERAND_REGISTER, spill_reg, -int_offset, NULL, R_JSR_SAVE_CODE); O_insert_fill_sequence (cb, op, op_list); } } #ifdef DEBUG fprintf (stderr, "\n"); fprintf (stderr, "int macro setjmp spill/fill ops: "); #endif L_assign_type_int_macro (spill_reg); for (variable = 0; variable < num_live_macros; variable++) { if (IS_INT_MACRO_TO_SPILL (live_macro_ids[variable])) { int_offset += 8; spill_reg->value.r = live_macro_ids[variable]; op_list = O_spill_reg (live_macro_ids[variable], L_OPERAND_MACRO, spill_reg, -int_offset, NULL, R_JSR_SAVE_CODE); O_insert_spill_sequence (cb, op, op_list); op_list = O_fill_reg (live_macro_ids[variable], L_OPERAND_MACRO, spill_reg, -int_offset, NULL, R_JSR_SAVE_CODE); O_insert_fill_sequence (cb, op, op_list); } } #ifdef DEBUG fprintf (stderr, "\n"); #endif L_delete_operand (spill_reg); /* * Put fp regs into local variable space. */ L_update_local_space_size (fn, fp_offset); /* * Put int regs into sync space -- must be managed by the UNAT */ if (*int_spill_start == int_offset) { /* No integers spilled */ *int_spill_end = *int_spill_start; return (0); } else { *int_spill_end = int_offset; return (1); } }
/*! \brief Finds loops in the CFG. Builds lp hdr, body and exit bb sets, and * puts this lp info in a PC_Loop struct, which is appended to the CFG lp list. * * \param cfg * control flow graph for the func being processed * * Multiple back edges coming into the same loop header are considered as one * loop. The loop body is a union of the bodies of the loops corresponding to * each one of these back edges. * * \return void */ void PC_FindLoops (PC_Graph cfg) { PC_Block h_bb; /* build dominator sets for each bb in the cfg */ PC_BuildDomSets (cfg); /* check each cfg bb in turn to see if it's a lp header bb */ for (h_bb = cfg->first_bb; h_bb; h_bb = h_bb->next) { PC_Flow be; PC_Loop *loop; int num_back_edge; int num_exit; int s_lp_head = -1; Set s_lp_body = Set_new (), s_lp_exits = Set_new (); /* check all edges coming into h_bb to see if they are back edges */ num_back_edge = 0; for (be = h_bb->p_flow; be; be = be->p_next_flow) { /* check to see if be is indeed a back edge */ if (PC_BB1DominatesBB2 (be->dest_bb, be->src_bb)) { PC_Block bb; Stack *st = New_Stack (); Set lp_body = Set_new (); num_back_edge++; s_lp_head = be->dest_bb->ID; if (be->src_bb->ID == be->dest_bb->ID) P_warn ("PC_FindNaturalLoop: back edge head & tail are same."); /* Build the set of all bbs in the lp body. */ lp_body = Set_add (lp_body, s_lp_head); if (!Set_in (lp_body, be->src_bb->ID)) { lp_body = Set_add (lp_body, be->src_bb->ID); Push_Top (st, be->src_bb); } while ((bb = Pop (st)) != ((void*)-1)) { PC_Flow fl; for (fl = bb->p_flow; fl; fl = fl->p_next_flow) { if (!Set_in (lp_body, fl->src_bb->ID)) { lp_body = Set_add (lp_body, fl->src_bb->ID); Push_Top (st, fl->src_bb); } } } /* the s_lp body is a union of all of these 'inner' lp bodies */ s_lp_body = Set_union (s_lp_body, lp_body); Clear_Stack (st); Set_dispose (lp_body); } } /* If a loop was found, build its set of exits bbs, and append it to the list of loops in the cfg. */ if (s_lp_head != -1) { int *s_lp_bod; int lp_size = 0, i; /* Build the set of all bbs that are exits out of the lp. */ s_lp_bod = (int *) calloc (Set_size (s_lp_body), sizeof (int)); lp_size = Set_2array (s_lp_body, s_lp_bod); num_exit = 0; for (i = 0; i < lp_size; i++) { PC_Block bb; PC_Flow fl; bb = PC_FindBlock (cfg, s_lp_bod[i]); for (fl = bb->s_flow; fl; fl = fl->s_next_flow) if (!Set_in (s_lp_body, fl->dest_bb->ID)) { num_exit++; s_lp_exits = Set_add (s_lp_exits, fl->dest_bb->ID); } } free (s_lp_bod); /* check for redundant loops */ { PC_Loop lp = NULL; int same = 0; for (lp = cfg->lp; lp; lp = lp->next) if (Set_same (s_lp_body, lp->body)) { same = 1; break; } if (same) { Set_dispose (s_lp_body); Set_dispose (s_lp_exits); continue; } } /* Create a new PC_Loop and append it to the current CFG loop list. */ loop = &cfg->lp; while (*loop) loop = &(*loop)->next; *loop = PC_NewLoop (s_lp_head, s_lp_body, s_lp_exits, num_back_edge, num_exit); cfg->lp_tree = PC_LoopTreeInsert (cfg->lp_tree, *loop, 1); } Set_dispose (s_lp_body); Set_dispose (s_lp_exits); } PC_SetBlockLoops (cfg); return; }
int L_global_memflow_multiloadstore_load (L_Func * fn, L_Cb * cb, L_Oper * oper) { return 0; #if 0 int change = 0; Set RAMB_ST, RAMB_JSR; Set RDEF_ST, RDEF_LD; if (!L_general_load_opcode (oper)) return 0; /* 02/07/03 REK Adding a check to make sure we don't touch a volatile * oper. */ if (L_EXTRACT_BIT_VAL (oper->flags, L_OPER_VOLATILE)) return 0; RDEF_ST = NULL; RDEF_LD = NULL; RAMB_ST = NULL; RAMB_JSR = NULL; /* Get all reaching stores */ RDEF_ST = L_get_mem_oper_RIN_defining_opers (oper, (MDF_RET_DEP | MDF_RET_STORES)); /* Get all reaching loads */ RDEF_LD = L_get_mem_oper_RIN_defining_opers (oper, (MDF_RET_DEP | MDF_RET_LOADS)); if (!Set_size (RDEF_LD) || !Set_size (RDEF_ST)) return change; fprintf (stderr, "\n\nMFMLSL: Examining load %d\n", oper->id); /* Are there any reaching, ambiguous stores */ RAMB_ST = L_get_mem_oper_RIN_defining_opers (oper, (MDF_RET_AMB | MDF_RET_STORES)); /* Are there any reaching, unsafe jsrs */ RAMB_JSR = L_get_mem_oper_RIN_defining_opers (oper, (MDF_RET_AMB | MDF_RET_JSRS)); fprintf (stderr, "MFMLSL: Dep Stores reach load %d ", oper->id); Set_print (stderr, "MSMLSL: ", RDEF_ST); fprintf (stderr, "MFMLSL: Dep Loads reach load %d ", oper->id); Set_print (stderr, "MSMLSL: ", RDEF_LD); fprintf (stderr, "MFMLSL: Amb Stores reach load %d ", oper->id); Set_print (stderr, "MSMLSL: ", RAMB_ST); fprintf (stderr, "MFMLSL: Unsafe jsrs reach load %d ", oper->id); Set_print (stderr, "MSMLSL: ", RAMB_JSR); if (!L_load_compatible_each_store (fn, oper, RDEF_ST)) { fprintf (stderr, "MFMLSL: Load is incompatible with a store\n"); Set_dispose (RDEF); Set_dispose (RDEF_LD); Set_dispose (RAMB_ST); Set_dispose (RAMB_JSR); return change; } if (!L_load_compatible_each_load (fn, oper, RDEF_LD)) { fprintf (stderr, "MFMLSL: Load is incompatible with a store\n"); Set_dispose (RDEF); Set_dispose (RDEF_LD); Set_dispose (RAMB_ST); Set_dispose (RAMB_JSR); return change; } if (!L_store_union_dominates_load (fn, cb, oper, Set_union (RDEF_LD, RDEF_ST))) { fprintf (stderr, "MFMLSL: Path to load exists not through a store/load\n"); Set_dispose (RDEF); Set_dispose (RDEF_LD); Set_dispose (RAMB_ST); Set_dispose (RAMB_JSR); return change; } if (!L_loadstore_union_postdominates_amb (fn, cb, oper, Set_union (RDEF_LD, RDEF_ST), Set_union (RAMB_ST, RAMB_JSR))) { fprintf (stderr, "MFMLSL: A amb st/jsr lies between ld/st and load \n"); Set_dispose (RDEF); Set_dispose (RDEF_LD); Set_dispose (RAMB_ST); Set_dispose (RAMB_JSR); return change; } /* Load can be removed, moves added */ fprintf (stderr, "MFMLSL: red Load %d can be converted\n", oper->id); Set_dispose (RDEF); Set_dispose (RDEF_LD); Set_dispose (RAMB_ST); Set_dispose (RAMB_JSR); return change; #endif }
int L_global_memflow_multistore_load (L_Func * fn, L_Cb * cb, L_Oper * oper) { int change = 0; Set RAMB, RDEF; L_Oper *use_op, *new_op; L_Cb *use_cb; L_Operand *src, *dest; int i, size; int *buf; if (!L_general_load_opcode (oper)) return 0; /* 02/07/03 REK Adding a check to make sure we don't touch a volatile * oper. */ if (L_EXTRACT_BIT_VAL (oper->flags, L_OPER_VOLATILE)) return 0; RAMB = NULL; RDEF = NULL; /*fprintf(stderr,"MFMSL: Examining load %d\n",oper->id); */ RDEF = L_get_mem_oper_RIN_set_rid (oper); /* Are there any reaching, ambiguous stores */ RAMB = L_get_mem_oper_RIN_defining_opers (oper, (MDF_RET_AMB | MDF_RET_STORES)); if (Set_size (RAMB)) { Set_dispose (RAMB); return change; } /* Are there any reaching, unsafe jsrs */ RAMB = L_get_mem_oper_RIN_defining_opers (oper, (MDF_RET_AMB | MDF_RET_JSRS)); if (Set_size (RAMB)) { Set_dispose (RAMB); return change; } /* Get all reaching stores */ RDEF = L_get_mem_oper_RIN_defining_opers (oper, (MDF_RET_DEP | MDF_RET_STORES)); if (!Set_size (RDEF)) { return change; } /* fprintf(stderr,"MFMSL: Dep Stores reach load %d\n",oper->id); Set_print( stderr, "MSMSL: ", RDEF); */ if (!L_load_compatible_each_store (fn, oper, RDEF)) { /* fprintf(stderr,"MFMSL: Load is incompatible with store\n"); */ return change; } if (!L_store_union_dominates_load (fn, cb, oper, RDEF)) { /* fprintf(stderr,"MFMSL: Path to load exists not through a store\n"); */ return change; } /* Load can be removed, moves added */ if (Lopti_debug_memflow) fprintf (stderr, "MFMSL: red Load %d can be converted\n", oper->id); dest = L_new_register_operand (++L_fn->max_reg_id, L_return_old_ctype (oper->dest[0]), L_PTYPE_NULL); /* convert load to a move */ change = 1; L_convert_to_extended_move (oper, L_copy_operand (oper->dest[0]), dest); /* add move to all stores */ size = Set_size (RDEF); buf = (int *) Lcode_malloc (sizeof (int) * size); Set_2array (RDEF, buf); for (i = 0; i < size; i++) { use_op = L_oper_hash_tbl_find_oper (fn->oper_hash_tbl, buf[i]); use_cb = L_oper_hash_tbl_find_cb (L_fn->oper_hash_tbl, buf[i]); if (Lopti_debug_memflow) fprintf (stderr, "MFMSL: Converting store %d cb %d\n", use_op->id, use_cb->id); /* change store to read from a new register */ src = use_op->src[2]; use_op->src[2] = L_copy_operand (dest); /* add new move before store */ new_op = L_create_move_using (L_copy_operand (dest), src, use_op); L_insert_oper_before (use_cb, use_op, new_op); } Lcode_free (buf); return change; }
/*! \brief Finds the natural loop corresponding to a back edge * * \param cfg * control flow graph for the func being processed * \param be * back edge going to the head of this particular natural loop * * *** CURRENTLY NOT IN USE *** * * \return void */ void PC_FindNaturalLoop (PC_Graph cfg, PC_Flow be) { PC_Loop *loop = NULL; PC_Block bb = NULL; PC_Flow fl = NULL; Stack *st = New_Stack (); int lp_head = be->dest_bb->ID, lp_size = 0, i; int *lp_bod; Set lp = Set_new (), lp_exits = Set_new (); int num_back_edge = 0; int num_exit = 0; if (be->src_bb->ID == be->dest_bb->ID) P_warn ("PC_FindNaturalLoop: head and tail of back edge are same."); /* Build the set of all bbs in the lp body. */ lp = Set_add (lp, lp_head); if (!Set_in (lp, be->src_bb->ID)) { lp = Set_add (lp, be->src_bb->ID); Push_Top (st, be->src_bb); } while ((bb = Pop (st)) != ((void*)-1)) { for (fl = bb->p_flow; fl; fl = fl->p_next_flow) { if (!Set_in (lp, fl->src_bb->ID)) { lp = Set_add (lp, fl->src_bb->ID); Push_Top (st, fl->src_bb); } } } /* Build the set of all bbs that are exits out of the lp. */ lp_bod = (int *) calloc (Set_size (lp), sizeof (int)); lp_size = Set_2array (lp, lp_bod); for (i = 0; i < lp_size; i++) { bb = PC_FindBlock (cfg, lp_bod[i]); for (fl = bb->s_flow; fl; fl = fl->s_next_flow) if (!Set_in (lp, fl->dest_bb->ID)) { lp_exits = Set_add (lp_exits, fl->dest_bb->ID); num_exit++; } } free (lp_bod); /* Append this loop to the list of loops in the PC_Graph. */ loop = &cfg->lp; while (*loop) { loop = &(*loop)->next; } *loop = PC_NewLoop (lp_head, lp, lp_exits, num_back_edge, num_exit); Set_dispose (lp); Set_dispose (lp_exits); }
int L_loop_check_load_for_linked_list_base (L_Loop * loop, int *pred, int *early, int *dp) { int change, i, num_cb, *loop_cb = NULL, num_out_cb, *out_cb = NULL, temp; int base_reg_id = -2, largest_value = 1; Lint loaded_reg_id = 0; L_Cb *cb, *header; L_Oper *op; L_Attr *attr; INT_Symbol_Table *int_table; INT_Symbol *int_symbol; /* setup cb array */ num_cb = Set_size (loop->loop_cb); if (num_cb > 0) { loop_cb = (int *) Lcode_malloc (sizeof (int) * num_cb); Set_2array (loop->loop_cb, loop_cb); } /* setup out_cb array */ num_out_cb = Set_size (loop->out_cb); if (num_out_cb > 0) { out_cb = (int *) Lcode_malloc (sizeof (int) * num_out_cb); Set_2array (loop->out_cb, out_cb); } L_find_all_ind_info (loop, loop_cb, num_cb); header = loop->header; for (i = 0; i < num_cb; i++) { cb = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, loop_cb[i]); for (op = cb->first_op; op != NULL; op = op->next_op) { if (!L_load_opcode (op)) continue; if (L_is_reg (op->dest[0])) { if (!InLint (loaded_reg_id, op->dest[0]->value.r)) loaded_reg_id = AppendLint (NewLint (op->dest[0]->value.r), loaded_reg_id); } if (L_find_attr (op->attr, L_SETUP_IMPLIED_REG) || L_find_attr (op->attr, L_DONT_PREDICT) || L_find_attr (op->attr, L_PREDICT)) continue; if ((base_reg_id == -2) && L_is_reg (op->dest[0]) && L_same_operand (op->dest[0], op->src[0])) { base_reg_id = op->src[0]->value.r; } } } change = 1; /* BCC - 9/7/98 * Initially, loaded_reg_id should only contain the register ids that are * destinations of load instructions. Here more register ids are added to * loaded_reg_id set if one of the instruction's source operands are loaded * from memory. */ while (change) { change = 0; for (i = 0; i < num_cb; i++) { cb = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, loop_cb[i]); for (op = cb->first_op; op != NULL; op = op->next_op) { if (L_store_opcode (op)) continue; if (!L_is_reg (op->dest[0])) continue; if (L_is_reg (op->src[0])) { if (InLint (loaded_reg_id, op->src[0]->value.r) && !InLint (loaded_reg_id, op->dest[0]->value.r)) { loaded_reg_id = AppendLint (NewLint (op->dest[0]->value.r), loaded_reg_id); change = 1; } } if (L_is_reg (op->src[1])) { if (InLint (loaded_reg_id, op->src[1]->value.r) && !InLint (loaded_reg_id, op->dest[0]->value.r)) { loaded_reg_id = AppendLint (NewLint (op->dest[0]->value.r), loaded_reg_id); change = 1; } } } } } /* Now, loaded_reg_id should contain all register ids whose contents are * loaded from memory in each iteration. If base_red_id is not set, search * for the largest group of load-dependent loads that use the same base * register. Then mark these loads as L_SETUP_IMPLIED_REG. */ if (base_reg_id == -2) { int_table = INT_new_symbol_table ("src_reg_table", 32); for (i = 0; i < num_cb; i++) { cb = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, loop_cb[i]); for (op = cb->first_op; op != NULL; op = op->next_op) { if (!L_load_opcode (op)) continue; if (L_find_attr (op->attr, L_SETUP_IMPLIED_REG) || L_find_attr (op->attr, L_DONT_PREDICT) || L_find_attr (op->attr, L_PREDICT)) continue; if (L_is_reg (op->src[0]) && L_is_int_constant (op->src[1]) && InLint (loaded_reg_id, op->src[0]->value.r)) { int_symbol = INT_find_symbol (int_table, op->src[0]->value.r); if (int_symbol) { #ifdef LP64_ARCHITECTURE temp = (int)((long)(int_symbol->data)); #else temp = (int) int_symbol->data; #endif temp++; #ifdef LP64_ARCHITECTURE int_symbol->data = (void *)((long)temp); #else int_symbol->data = (void *) temp; #endif } else INT_add_symbol (int_table, op->src[0]->value.r, (void *) 1); } } } for (int_symbol = int_table->head_symbol; int_symbol; int_symbol = int_symbol->next_symbol) { #ifdef LP64_ARCHITECTURE if ((int)((long)(int_symbol->data)) > largest_value) #else if ((int) int_symbol->data > largest_value) #endif { #ifdef LP64_ARCHITECTURE largest_value = (int)((long)(int_symbol->data)); #else largest_value = (int) int_symbol->data; #endif base_reg_id = int_symbol->value; } } INT_delete_symbol_table (int_table, 0); } for (i = 0; i < num_cb; i++) { cb = L_cb_hash_tbl_find (L_fn->cb_hash_tbl, loop_cb[i]); for (op = cb->first_op; op != NULL; op = op->next_op) { if (!L_load_opcode (op)) continue; if (L_find_attr (op->attr, L_SETUP_IMPLIED_REG) || L_find_attr (op->attr, L_DONT_PREDICT) || L_find_attr (op->attr, L_PREDICT)) continue; if (L_is_reg (op->src[0]) && L_is_int_constant (op->src[1])) { if (op->src[0]->value.r == base_reg_id) { attr = L_new_attr (L_SETUP_IMPLIED_REG, 0); op->attr = L_concat_attr (op->attr, attr); (*early)++; } else if (InLint (loaded_reg_id, op->src[0]->value.r)) { attr = L_new_attr (L_DONT_PREDICT, 0); op->attr = L_concat_attr (op->attr, attr); (*dp)++; } else { attr = L_new_attr (L_PREDICT, 0); op->attr = L_concat_attr (op->attr, attr); (*pred)++; } } else if ((L_is_reg (op->src[0]) && InLint (loaded_reg_id, op->src[0]->value.r)) || (L_is_reg (op->src[1]) && InLint (loaded_reg_id, op->src[1]->value.r))) { attr = L_new_attr (L_DONT_PREDICT, 0); op->attr = L_concat_attr (op->attr, attr); (*dp)++; } else { attr = L_new_attr (L_PREDICT, 0); op->attr = L_concat_attr (op->attr, attr); (*pred)++; } } } if (loop_cb != NULL) Lcode_free (loop_cb); if (out_cb != NULL) Lcode_free (out_cb); if (loaded_reg_id) FreeLint (loaded_reg_id); return change; }
void LB_elim_loop_backedges (L_Func * fn, L_Loop * loop) { L_Cb *loop_header_cb = loop->header, *loop_end_cb, *cb; L_Flow *src_flow, *dst_flow, *back_edge_flow, *header_src_flow; L_Oper *oper, *branch; int num_back_edges, *back_edge_cb, i; /* We will only modify loops with more than one back edge */ if ((num_back_edges = Set_size (loop->back_edge_cb)) <= 1) return; #ifdef DEBUG fprintf (stderr, "Loop %d has %d backedges\n", loop->id, num_back_edges); Set_print (stderr, "backedges", loop->back_edge_cb); #endif if (LB_functionally_equivalent_cbs (loop->back_edge_cb) && !Set_in (loop->back_edge_cb, loop->header->id)) { #ifdef DEBUG fprintf (stderr, "Loop backedge cbs are equivalent!!\n"); #endif LB_combine_equivalent_backedges (loop); return; } #ifdef DEBUG fprintf (stderr, "Loop backedge cbs are NOT equivalent!!\n"); #endif /* Create a cb with a back-edge to the loop header cb. */ loop_end_cb = L_create_cb (0.0); header_src_flow = L_new_flow (1, loop_end_cb, loop_header_cb, 0.0); loop_header_cb->src_flow = L_concat_flow (loop_header_cb->src_flow, header_src_flow); back_edge_flow = L_new_flow (1, loop_end_cb, loop_header_cb, 0.0); loop_end_cb->dest_flow = L_concat_flow (loop_end_cb->dest_flow, back_edge_flow); L_insert_cb_after (fn, fn->last_cb, loop_end_cb); /* Create the jump instruction that leads to the header cb */ oper = L_create_new_op (Lop_JUMP); oper->src[0] = L_new_cb_operand (loop_header_cb); L_insert_oper_after (loop_end_cb, loop_end_cb->first_op, oper); #ifdef DEBUG fprintf (stderr, "created cb %d, placed it after cb %d\n", loop_end_cb->id, loop_end_cb->prev_cb->id); #endif /* * Loop through all loop back-edge cbs and make them branch to the * to the new end loop cb. */ back_edge_cb = (int *) Lcode_malloc (sizeof (int) * num_back_edges); Set_2array (loop->back_edge_cb, back_edge_cb); for (i = 0; i < num_back_edges; i++) { cb = L_cb_hash_tbl_find (fn->cb_hash_tbl, back_edge_cb[i]); /* * Find the destination flow arc in the current cb corresponding to the * loop back edge. */ for (dst_flow = cb->dest_flow; dst_flow; dst_flow = dst_flow->next_flow) { if (dst_flow->dst_cb != loop_header_cb) continue; /* * Find the src flow arc in the loop header cb corresponding to the * current back edge and delete it. */ src_flow = L_find_flow (loop_header_cb->src_flow, dst_flow->cc, dst_flow->src_cb, dst_flow->dst_cb); loop_header_cb->src_flow = L_delete_flow (loop_header_cb->src_flow, src_flow); /* Modify the flow arc and branch target for the branch */ branch = L_find_branch_for_flow (cb, dst_flow); #ifdef DEBUG fprintf (stderr, "\t (cb %d) branch oper %d\n", cb->id, branch->id); fprintf (stderr, "\t"); L_print_oper (stderr, branch); #endif if (branch) { L_change_branch_dest (branch, dst_flow->dst_cb, loop_end_cb); } else { L_Oper *new_op; new_op = L_create_new_op (Lop_JUMP); new_op->src[0] = L_new_cb_operand (loop_end_cb); L_insert_oper_after (cb, cb->last_op, new_op); } dst_flow->dst_cb = loop_end_cb; src_flow = L_new_flow (dst_flow->cc, dst_flow->src_cb, dst_flow->dst_cb, dst_flow->weight); loop_end_cb->src_flow = L_concat_flow (loop_end_cb->src_flow, src_flow); loop_end_cb->weight += src_flow->weight; back_edge_flow->weight += src_flow->weight; header_src_flow->weight += src_flow->weight; } } /* Add the new back-edge cb to the back edge cb list for the loop */ loop->back_edge_cb = Set_dispose (loop->back_edge_cb); loop->back_edge_cb = Set_add (loop->back_edge_cb, loop_end_cb->id); loop->loop_cb = Set_add (loop->loop_cb, loop_end_cb->id); /* free up space */ Lcode_free (back_edge_cb); }