static void erase_matching_seqs (void) { seq_block sb; matching_seq mseq; rtx insn; basic_block bb; rtx retlabel, saveinsn, callinsn; int i; for (sb = seq_blocks; sb; sb = sb->next_seq_block) { for (mseq = sb->matching_seqs; mseq; mseq = mseq->next_matching_seq) { insn = mseq->insn; bb = BLOCK_FOR_INSN (insn); /* Get the label after the sequence. This will be the return address. The label will be referenced using a symbol_ref so protect it from deleting. */ retlabel = block_label_after (insn); LABEL_PRESERVE_P (retlabel) = 1; /* Delete the insns of the sequence. */ for (i = 0; i < sb->length; i++) insn = prev_insn_in_block (insn); delete_basic_block (split_block_and_df_analyze (bb, insn)); /* Emit an insn saving the return address to the link register before the deleted sequence. */ saveinsn = emit_insn_after (gen_move_insn (pattern_seqs->link_reg, gen_symbol_ref_rtx_for_label (retlabel)), BB_END (bb)); BLOCK_FOR_INSN (saveinsn) = bb; /* Emit a jump to the appropriate part of the pattern sequence after the save insn. Also update the basic block. */ callinsn = emit_jump_insn_after (gen_jump (sb->label), saveinsn); JUMP_LABEL (callinsn) = sb->label; LABEL_NUSES (sb->label)++; BLOCK_FOR_INSN (callinsn) = bb; BB_END (bb) = callinsn; /* Maintain control flow and liveness information. */ SET_REGNO_REG_SET (df_get_live_out (bb), REGNO (pattern_seqs->link_reg)); emit_barrier_after (BB_END (bb)); make_single_succ_edge (bb, BLOCK_FOR_INSN (sb->label), 0); IOR_REG_SET (df_get_live_out (bb), df_get_live_in (BLOCK_FOR_INSN (sb->label))); make_edge (BLOCK_FOR_INSN (seq_blocks->label), BLOCK_FOR_INSN (retlabel), EDGE_ABNORMAL); } } }
static void split_blocks_after_seqs (void) { seq_block sb; matching_seq mseq; block_label_after (pattern_seqs->insn); for (sb = seq_blocks; sb; sb = sb->next_seq_block) { for (mseq = sb->matching_seqs; mseq; mseq = mseq->next_matching_seq) { block_label_after (mseq->insn); IOR_REG_SET (df_get_live_out (BLOCK_FOR_INSN (pattern_seqs->insn)), df_get_live_out (BLOCK_FOR_INSN (mseq->insn))); } } }
/* The confluence function used by the DF equation solver to propagate live info from successor to predecessor on edge E according to the following equation: bb.liveout = 0 for entry block | OR (livein of successors) */ static bool live_con_fun_n (edge e) { basic_block bb = e->src; basic_block dest = e->dest; bitmap bb_liveout = df_get_live_out (bb); bitmap dest_livein = df_get_live_in (dest); return bitmap_ior_and_compl_into (bb_liveout, dest_livein, &all_hard_regs_bitmap); }
/* The transfer function used by the DF equation solver to propagate live info through block with BB_INDEX according to the following equation: bb.livein = (bb.liveout - bb.kill) OR bb.gen */ static bool live_trans_fun (int bb_index) { basic_block bb = get_bb_data_by_index (bb_index)->bb; bitmap bb_liveout = df_get_live_out (bb); bitmap bb_livein = df_get_live_in (bb); bb_data_t bb_info = get_bb_data (bb); bitmap_and_compl (&temp_bitmap, bb_liveout, &all_hard_regs_bitmap); return bitmap_ior_and_compl (bb_livein, &bb_info->gen_pseudos, &temp_bitmap, &bb_info->killed_pseudos); }
static void split_pattern_seq (void) { rtx insn; basic_block bb; rtx retlabel, retjmp, saveinsn; int i; seq_block sb; insn = pattern_seqs->insn; bb = BLOCK_FOR_INSN (insn); /* Get the label after the sequence. This will be the return address. The label will be referenced using a symbol_ref so protect it from deleting. */ retlabel = block_label_after (insn); LABEL_PRESERVE_P (retlabel) = 1; /* Emit an indirect jump via the link register after the sequence acting as the return insn. Also emit a barrier and update the basic block. */ if (!find_reg_note (BB_END (bb), REG_NORETURN, NULL)) retjmp = emit_jump_insn_after (gen_indirect_jump (pattern_seqs->link_reg), BB_END (bb)); emit_barrier_after (BB_END (bb)); /* Replace all outgoing edges with a new one to the block of RETLABEL. */ while (EDGE_COUNT (bb->succs) != 0) remove_edge (EDGE_SUCC (bb, 0)); make_edge (bb, BLOCK_FOR_INSN (retlabel), EDGE_ABNORMAL); /* Split the sequence according to SEQ_BLOCKS and cache the label of the resulting basic blocks. */ i = 0; for (sb = seq_blocks; sb; sb = sb->next_seq_block) { for (; i < sb->length; i++) insn = prev_insn_in_block (insn); sb->label = block_label (split_block_and_df_analyze (bb, insn)); } /* Emit an insn saving the return address to the link register before the sequence. */ saveinsn = emit_insn_after (gen_move_insn (pattern_seqs->link_reg, gen_symbol_ref_rtx_for_label (retlabel)), BB_END (bb)); /* Update liveness info. */ SET_REGNO_REG_SET (df_get_live_out (bb), REGNO (pattern_seqs->link_reg)); }
static bool commit_mode_sets (struct edge_list *edge_list, int e, struct bb_info *info) { bool need_commit = false; for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--) { edge eg = INDEX_EDGE (edge_list, ed); int mode; if ((mode = (int)(intptr_t)(eg->aux)) != -1) { HARD_REG_SET live_at_edge; basic_block src_bb = eg->src; int cur_mode = info[src_bb->index].mode_out; rtx_insn *mode_set; REG_SET_TO_HARD_REG_SET (live_at_edge, df_get_live_out (src_bb)); rtl_profile_for_edge (eg); start_sequence (); targetm.mode_switching.emit (e, mode, cur_mode, live_at_edge); mode_set = get_insns (); end_sequence (); default_rtl_profile (); /* Do not bother to insert empty sequence. */ if (mode_set == NULL) continue; /* We should not get an abnormal edge here. */ gcc_assert (! (eg->flags & EDGE_ABNORMAL)); need_commit = true; insert_insn_on_edge (mode_set, eg); } } return need_commit; }
/* The confluence function used by the DF equation solver to set up live info for a block BB without predecessor. */ static void live_con_fun_0 (basic_block bb) { bitmap_and_into (df_get_live_out (bb), &all_hard_regs_bitmap); }
static unsigned int copyprop_hardreg_forward (void) { struct value_data *all_vd; basic_block bb; sbitmap visited; bool analyze_called = false; all_vd = XNEWVEC (struct value_data, last_basic_block); visited = sbitmap_alloc (last_basic_block); bitmap_clear (visited); if (MAY_HAVE_DEBUG_INSNS) debug_insn_changes_pool = create_alloc_pool ("debug insn changes pool", sizeof (struct queued_debug_insn_change), 256); FOR_EACH_BB (bb) { bitmap_set_bit (visited, bb->index); /* If a block has a single predecessor, that we've already processed, begin with the value data that was live at the end of the predecessor block. */ /* ??? Ought to use more intelligent queuing of blocks. */ if (single_pred_p (bb) && bitmap_bit_p (visited, single_pred (bb)->index) && ! (single_pred_edge (bb)->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))) { all_vd[bb->index] = all_vd[single_pred (bb)->index]; if (all_vd[bb->index].n_debug_insn_changes) { unsigned int regno; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) { if (all_vd[bb->index].e[regno].debug_insn_changes) { all_vd[bb->index].e[regno].debug_insn_changes = NULL; if (--all_vd[bb->index].n_debug_insn_changes == 0) break; } } } } else init_value_data (all_vd + bb->index); copyprop_hardreg_forward_1 (bb, all_vd + bb->index); } if (MAY_HAVE_DEBUG_INSNS) { FOR_EACH_BB (bb) if (bitmap_bit_p (visited, bb->index) && all_vd[bb->index].n_debug_insn_changes) { unsigned int regno; bitmap live; if (!analyze_called) { df_analyze (); analyze_called = true; } live = df_get_live_out (bb); for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (all_vd[bb->index].e[regno].debug_insn_changes) { if (REGNO_REG_SET_P (live, regno)) apply_debug_insn_changes (all_vd + bb->index, regno); if (all_vd[bb->index].n_debug_insn_changes == 0) break; } } free_alloc_pool (debug_insn_changes_pool); } sbitmap_free (visited); free (all_vd); return 0; }
/* The major function for aggressive pseudo coalescing of moves only if the both pseudos were spilled and not special reload pseudos. */ bool lra_coalesce (void) { basic_block bb; rtx mv, set, insn, next, *sorted_moves; int i, mv_num, sregno, dregno; int coalesced_moves; int max_regno = max_reg_num (); bitmap_head involved_insns_bitmap; timevar_push (TV_LRA_COALESCE); if (lra_dump_file != NULL) fprintf (lra_dump_file, "\n********** Pseudos coalescing #%d: **********\n\n", ++lra_coalesce_iter); first_coalesced_pseudo = XNEWVEC (int, max_regno); next_coalesced_pseudo = XNEWVEC (int, max_regno); for (i = 0; i < max_regno; i++) first_coalesced_pseudo[i] = next_coalesced_pseudo[i] = i; sorted_moves = XNEWVEC (rtx, get_max_uid ()); mv_num = 0; /* Collect moves. */ coalesced_moves = 0; FOR_EACH_BB (bb) { FOR_BB_INSNS_SAFE (bb, insn, next) if (INSN_P (insn) && (set = single_set (insn)) != NULL_RTX && REG_P (SET_DEST (set)) && REG_P (SET_SRC (set)) && (sregno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER && (dregno = REGNO (SET_DEST (set))) >= FIRST_PSEUDO_REGISTER && mem_move_p (sregno, dregno) && coalescable_pseudo_p (sregno) && coalescable_pseudo_p (dregno) && ! side_effects_p (set) && !(lra_intersected_live_ranges_p (lra_reg_info[sregno].live_ranges, lra_reg_info[dregno].live_ranges))) sorted_moves[mv_num++] = insn; } qsort (sorted_moves, mv_num, sizeof (rtx), move_freq_compare_func); /* Coalesced copies, most frequently executed first. */ bitmap_initialize (&coalesced_pseudos_bitmap, ®_obstack); bitmap_initialize (&involved_insns_bitmap, ®_obstack); for (i = 0; i < mv_num; i++) { mv = sorted_moves[i]; set = single_set (mv); lra_assert (set != NULL && REG_P (SET_SRC (set)) && REG_P (SET_DEST (set))); sregno = REGNO (SET_SRC (set)); dregno = REGNO (SET_DEST (set)); if (first_coalesced_pseudo[sregno] == first_coalesced_pseudo[dregno]) { coalesced_moves++; if (lra_dump_file != NULL) fprintf (lra_dump_file, " Coalescing move %i:r%d-r%d (freq=%d)\n", INSN_UID (mv), sregno, dregno, BLOCK_FOR_INSN (mv)->frequency); /* We updated involved_insns_bitmap when doing the merge. */ } else if (!(lra_intersected_live_ranges_p (lra_reg_info[first_coalesced_pseudo[sregno]].live_ranges, lra_reg_info[first_coalesced_pseudo[dregno]].live_ranges))) { coalesced_moves++; if (lra_dump_file != NULL) fprintf (lra_dump_file, " Coalescing move %i:r%d(%d)-r%d(%d) (freq=%d)\n", INSN_UID (mv), sregno, ORIGINAL_REGNO (SET_SRC (set)), dregno, ORIGINAL_REGNO (SET_DEST (set)), BLOCK_FOR_INSN (mv)->frequency); bitmap_ior_into (&involved_insns_bitmap, &lra_reg_info[sregno].insn_bitmap); bitmap_ior_into (&involved_insns_bitmap, &lra_reg_info[dregno].insn_bitmap); merge_pseudos (sregno, dregno); } } bitmap_initialize (&used_pseudos_bitmap, ®_obstack); FOR_EACH_BB (bb) { update_live_info (df_get_live_in (bb)); update_live_info (df_get_live_out (bb)); FOR_BB_INSNS_SAFE (bb, insn, next) if (INSN_P (insn) && bitmap_bit_p (&involved_insns_bitmap, INSN_UID (insn))) { if (! substitute (&insn)) continue; lra_update_insn_regno_info (insn); if ((set = single_set (insn)) != NULL_RTX && set_noop_p (set)) { /* Coalesced move. */ if (lra_dump_file != NULL) fprintf (lra_dump_file, " Removing move %i (freq=%d)\n", INSN_UID (insn), BLOCK_FOR_INSN (insn)->frequency); lra_set_insn_deleted (insn); } } } bitmap_clear (&used_pseudos_bitmap); bitmap_clear (&involved_insns_bitmap); bitmap_clear (&coalesced_pseudos_bitmap); if (lra_dump_file != NULL && coalesced_moves != 0) fprintf (lra_dump_file, "Coalesced Moves = %d\n", coalesced_moves); free (sorted_moves); free (next_coalesced_pseudo); free (first_coalesced_pseudo); timevar_pop (TV_LRA_COALESCE); return coalesced_moves != 0; }