Robin Dapp <rd...@linux.ibm.com> writes: > noce_convert_multiple_sets creates temporaries for the destination of > every emitted cmov and expects subsequent passes to get rid of them. This > does not happen every time and even if the temporaries are removed, code > generation can be affected adversely. In this patch, temporaries are > only created if the destination of a set is used in an emitted condition > check.
Still digesting the series, but a couple of implementation questions: > > --- > gcc/ifcvt.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++--- > 1 file changed, 51 insertions(+), 3 deletions(-) > > diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c > index e95ff9ee9b0..253b8a96c1a 100644 > --- a/gcc/ifcvt.c > +++ b/gcc/ifcvt.c > @@ -99,6 +99,10 @@ static int dead_or_predicable (basic_block, basic_block, > basic_block, > edge, int); > static void noce_emit_move_insn (rtx, rtx); > static rtx_insn *block_has_only_trap (basic_block); > +static void check_need_temps (basic_block bb, > + hash_map<rtx, bool> *need_temp, > + rtx cond); > + > > /* Count the number of non-jump active insns in BB. */ > > @@ -3145,6 +3149,12 @@ noce_convert_multiple_sets (struct noce_if_info > *if_info) > auto_vec<rtx_insn *> unmodified_insns; > int count = 0; > > + hash_map<rtx, bool> need_temps; > + > + check_need_temps (then_bb, &need_temps, cond); Is the separate need_temps scan required for correctness? It looked like we could test: if (reg_overlap_mentioned_p (dest, cond)) ... on-the-fly during the main noce_convert_multiple_sets loop. > + > + hash_map<rtx, bool> temps_created; > + > FOR_BB_INSNS (then_bb, insn) > { > /* Skip over non-insns. */ > @@ -3155,10 +3165,20 @@ noce_convert_multiple_sets (struct noce_if_info > *if_info) > gcc_checking_assert (set); > > rtx target = SET_DEST (set); > - rtx temp = gen_reg_rtx (GET_MODE (target)); > rtx new_val = SET_SRC (set); > rtx old_val = target; > > + rtx dest = SET_DEST (set); > + > + rtx temp; > + if (need_temps.get (dest)) > + { > + temp = gen_reg_rtx (GET_MODE (target)); > + temps_created.put (target, true); > + } > + else > + temp = target; > + > /* If we were supposed to read from an earlier write in this block, > we've changed the register allocation. Rewire the read. While > we are looking, also try to catch a swap idiom. */ > @@ -3242,8 +3262,8 @@ noce_convert_multiple_sets (struct noce_if_info > *if_info) > > /* Now fixup the assignments. */ > for (int i = 0; i < count; i++) > - noce_emit_move_insn (targets[i], temporaries[i]); > - > + if (temps_created.get(targets[i]) && targets[i] != temporaries[i]) > + noce_emit_move_insn (targets[i], temporaries[i]); Would it work to set temporaries[i] to targets[i] whenever a temporary isn't needed, and avoid temps_created? Thanks, Richard > > /* Actually emit the sequence if it isn't too expensive. */ > rtx_insn *seq = get_insns (); > @@ -3749,6 +3769,34 @@ check_cond_move_block (basic_block bb, > return TRUE; > } > > +/* Check for which sets we need to emit temporaries to hold the destination > of > + a conditional move. */ > +static void > +check_need_temps (basic_block bb, hash_map<rtx, bool> *need_temp, rtx cond) > +{ > + rtx_insn *insn; > + > + FOR_BB_INSNS (bb, insn) > + { > + rtx set, dest; > + > + if (!active_insn_p (insn)) > + continue; > + > + set = single_set (insn); > + if (set == NULL_RTX) > + continue; > + > + dest = SET_DEST (set); > + > + /* noce_emit_cmove will emit the condition check every time it is > called > + so we need a temp register if the destination is modified. */ > + if (reg_overlap_mentioned_p (dest, cond)) > + need_temp->put (dest, true); > + } > +} > + > + > /* Given a basic block BB suitable for conditional move conversion, > a condition COND, and pointer maps THEN_VALS and ELSE_VALS containing > the register values depending on COND, emit the insns in the block as