Index: regrename.c =================================================================== --- regrename.c.orig +++ regrename.c @@ -785,6 +785,92 @@ scan_rtx (rtx insn, rtx *loc, enum reg_c } } +/* Hide operands of the current insn (of which there are N_OPS) by + substituting cc0 for them. + Previous values are stored in the OLD_OPERANDS and OLD_DUPS. + If INOUT_ONLY is set, we only do this for OP_INOUT type operands. */ + +static void +hide_operands (int n_ops, rtx *old_operands, rtx *old_dups, + bool inout_only) +{ + int i; + for (i = 0; i < n_ops; i++) + { + old_operands[i] = recog_data.operand[i]; + /* Don't squash match_operator or match_parallel here, since + we don't know that all of the contained registers are + reachable by proper operands. */ + if (recog_data.constraints[i][0] == '\0') + continue; + if (!inout_only || recog_data.operand_type[i] == OP_INOUT) + *recog_data.operand_loc[i] = cc0_rtx; + } + for (i = 0; i < recog_data.n_dups; i++) + { + int opn = recog_data.dup_num[i]; + old_dups[i] = *recog_data.dup_loc[i]; + if (!inout_only || recog_data.operand_type[opn] == OP_INOUT) + *recog_data.dup_loc[i] = cc0_rtx; + } +} + +/* Undoes the substitution performed by hide_operands. INSN is the insn we + are processing; the arguments are the same as in hide_operands. */ + +static void +restore_operands (rtx insn, int n_ops, rtx *old_operands, rtx *old_dups) +{ + int i; + for (i = 0; i < recog_data.n_dups; i++) + *recog_data.dup_loc[i] = old_dups[i]; + for (i = 0; i < n_ops; i++) + *recog_data.operand_loc[i] = old_operands[i]; + if (recog_data.n_dups) + df_insn_rescan (insn); +} + +/* For each output operands of INSN, call scan_rtx to create a new + open chain. */ + +static void +record_out_operands (rtx insn) +{ + int n_ops = recog_data.n_operands; + int alt = which_alternative; + + int i; + + for (i = 0; i < n_ops + recog_data.n_dups; i++) + { + int opn = i < n_ops ? i : recog_data.dup_num[i - n_ops]; + rtx *loc = (i < n_ops + ? recog_data.operand_loc[opn] + : recog_data.dup_loc[i - n_ops]); + rtx op = *loc; + enum reg_class cl = recog_op_alt[opn][alt].cl; + struct du_head *prev_open = open_chains; + + if (recog_data.operand_type[opn] == OP_OUT) + scan_rtx (insn, loc, cl, mark_write, OP_OUT, + recog_op_alt[opn][alt].earlyclobber); + + /* ??? Many targets have output constraints on the SET_DEST + of a call insn, which is stupid, since these are certainly + ABI defined hard registers. For these, and for asm operands + that originally referenced hard registers, we must record that + the chain cannot be renamed. */ + if (CALL_P (insn) + || (asm_noperands (PATTERN (insn)) > 0 + && REG_P (op) + && REGNO (op) == ORIGINAL_REGNO (op))) + { + if (prev_open != open_chains) + open_chains->first->cl = NO_REGS; + } + } +} + /* Build def/use chain. */ static struct du_head * @@ -855,31 +941,10 @@ build_def_use (basic_block bb) We do this by munging all operands into CC0, and closing everything remaining. */ - for (i = 0; i < n_ops; i++) - { - old_operands[i] = recog_data.operand[i]; - /* Don't squash match_operator or match_parallel here, since - we don't know that all of the contained registers are - reachable by proper operands. */ - if (recog_data.constraints[i][0] == '\0') - continue; - *recog_data.operand_loc[i] = cc0_rtx; - } - for (i = 0; i < recog_data.n_dups; i++) - { - old_dups[i] = *recog_data.dup_loc[i]; - *recog_data.dup_loc[i] = cc0_rtx; - } - + hide_operands (n_ops, old_operands, old_dups, false); scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_all_read, OP_IN, 0); - - for (i = 0; i < recog_data.n_dups; i++) - *recog_data.dup_loc[i] = old_dups[i]; - for (i = 0; i < n_ops; i++) - *recog_data.operand_loc[i] = old_operands[i]; - if (recog_data.n_dups) - df_insn_rescan (insn); + restore_operands (insn, n_ops, old_operands, old_dups); /* Step 2B: Can't rename function call argument registers. */ if (CALL_P (insn) && CALL_INSN_FUNCTION_USAGE (insn)) @@ -950,63 +1015,12 @@ build_def_use (basic_block bb) step 2, we hide in-out operands, since we do not want to close these chains. */ - for (i = 0; i < n_ops; i++) - { - old_operands[i] = recog_data.operand[i]; - if (recog_data.operand_type[i] == OP_INOUT) - *recog_data.operand_loc[i] = cc0_rtx; - } - for (i = 0; i < recog_data.n_dups; i++) - { - int opn = recog_data.dup_num[i]; - old_dups[i] = *recog_data.dup_loc[i]; - if (recog_data.operand_type[opn] == OP_INOUT) - *recog_data.dup_loc[i] = cc0_rtx; - } - + hide_operands (n_ops, old_operands, old_dups, true); scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_write, OP_IN, 0); - - for (i = 0; i < recog_data.n_dups; i++) - *recog_data.dup_loc[i] = old_dups[i]; - for (i = 0; i < n_ops; i++) - *recog_data.operand_loc[i] = old_operands[i]; + restore_operands (insn, n_ops, old_operands, old_dups); /* Step 6: Begin new chains for writes inside operands. */ - /* ??? Many targets have output constraints on the SET_DEST - of a call insn, which is stupid, since these are certainly - ABI defined hard registers. Don't change calls at all. - Similarly take special care for asm statement that originally - referenced hard registers. */ - if (asm_noperands (PATTERN (insn)) > 0) - { - for (i = 0; i < n_ops; i++) - if (recog_data.operand_type[i] == OP_OUT) - { - rtx *loc = recog_data.operand_loc[i]; - rtx op = *loc; - enum reg_class cl = recog_op_alt[i][alt].cl; - - if (REG_P (op) - && REGNO (op) == ORIGINAL_REGNO (op)) - continue; - - scan_rtx (insn, loc, cl, mark_write, OP_OUT, - recog_op_alt[i][alt].earlyclobber); - } - } - else if (!CALL_P (insn)) - for (i = 0; i < n_ops + recog_data.n_dups; i++) - { - int opn = i < n_ops ? i : recog_data.dup_num[i - n_ops]; - rtx *loc = (i < n_ops - ? recog_data.operand_loc[opn] - : recog_data.dup_loc[i - n_ops]); - enum reg_class cl = recog_op_alt[opn][alt].cl; - - if (recog_data.operand_type[opn] == OP_OUT) - scan_rtx (insn, loc, cl, mark_write, OP_OUT, - recog_op_alt[opn][alt].earlyclobber); - } + record_out_operands (insn); /* Step 6B: Record destination regs in REG_FRAME_RELATED_EXPR notes for update. */