?? combine.c
字號(hào):
|| (i1 && GET_CODE (i1) == NOTE)) return 0; /* Don't combine across a CALL_INSN, because that would possibly change whether the life span of some REGs crosses calls or not, and it is a pain to update that information. */ if (INSN_CUID (i2) < last_call_cuid || (i1 && INSN_CUID (i1) < last_call_cuid)) return 0; /* Can combine only if previous insn is a SET of a REG, a SUBREG or CC0. That REG must be either set or dead by the final instruction (so that we can safely forget about setting it). Also test use_crosses_set_p to make sure that the value that is to be substituted for the register does not use any registers whose values alter in between. Do not try combining with moves from one register to another since it is better to let them be tied by register allocation. (There is a switch to permit such combination; except the insns that copy a function value into another register are never combined because moving that too far away from the function call could cause something else to be stored in that register in the interim.) A set of a SUBREG is considered as if it were a set from SUBREG. Thus, (SET (SUBREG:X (REG:Y...)) (something:X...)) is handled by substituting (SUBREG:Y (something:X...)) for (REG:Y...). */ if (GET_CODE (PATTERN (i2)) != SET) return 0; i2dest = SET_DEST (PATTERN (i2)); i2src = SET_SRC (PATTERN (i2)); if (GET_CODE (i2dest) == SUBREG) { i2dest = SUBREG_REG (i2dest); i2src = gen_rtx (SUBREG, GET_MODE (i2dest), i2src, 0); } /* Don't eliminate a store in the stack pointer. */ if (i2dest == stack_pointer_rtx) return 0; /* Don't install a subreg involving two modes not tieable. It can worsen register allocation, and can even make invalid reload insns, since the reg inside may need to be copied from in the outside mode, and that may be invalid if it is an fp reg copied in integer mode. */ if (GET_CODE (i2src) == SUBREG && ! MODES_TIEABLE_P (GET_MODE (i2src), GET_MODE (SUBREG_REG (i2src)))) return 0; if (GET_CODE (i2dest) != CC0 && (GET_CODE (i2dest) != REG || (GET_CODE (i2src) == REG /* Do allow the combination of y = x; x = y; (with x dead) because the result will turn into nothing. */ && !(GET_CODE (PATTERN (i3)) == SET && i2src == SET_DEST (PATTERN (i3))) && (!flag_combine_regs /* Don't substitute a function value reg for any other. */ || FUNCTION_VALUE_REGNO_P (REGNO (i2src)))) || GET_CODE (i2src) == CALL /* Don't substitute into an incremented register. */ || find_reg_note (i3, REG_INC, i2dest) || use_crosses_set_p (i2src, INSN_CUID (i2)))) return 0; if (GET_CODE (i2src) == ASM_OPERANDS && MEM_VOLATILE_P (i2src)) return 0; /* Don't substitute for a register intended as a clobberable operand. */ if (GET_CODE (PATTERN (i3)) == PARALLEL) for (i = 0; i < XVECLEN (PATTERN (i3), 0); i++) if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER && XEXP (XVECEXP (PATTERN (i3), 0, i), 0) == i2dest) return 0; if (i1 != 0) { if (GET_CODE (PATTERN (i1)) != SET) return 0; i1dest = SET_DEST (PATTERN (i1)); i1src = SET_SRC (PATTERN (i1)); if (GET_CODE (i1dest) == SUBREG) { i1dest = SUBREG_REG (i1dest); i1src = gen_rtx (SUBREG, GET_MODE (i1dest), i1src, 0); } if (i1dest == stack_pointer_rtx) return 0; if (GET_CODE (i1src) == SUBREG && ! MODES_TIEABLE_P (GET_MODE (i1src), GET_MODE (SUBREG_REG (i1src)))) return 0; if (GET_CODE (i1dest) != CC0 && (GET_CODE (i1dest) != REG || (GET_CODE (i1src) == REG && (!flag_combine_regs || FUNCTION_VALUE_REGNO_P (REGNO (i1src)))) || GET_CODE (i1src) == CALL || find_reg_note (i3, REG_INC, i1dest) || find_reg_note (i2, REG_INC, i1dest) || use_crosses_set_p (i1src, INSN_CUID (i1)))) return 0; if (GET_CODE (i1src) == ASM_OPERANDS && MEM_VOLATILE_P (i1src)) return 0; /* Don't substitute for a register intended as a clobberable operand. */ if (GET_CODE (PATTERN (i3)) == PARALLEL) for (i = 0; i < XVECLEN (PATTERN (i3), 0); i++) if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER && XEXP (XVECEXP (PATTERN (i3), 0, i), 0) == i1dest) return 0; } /* If it is better that two different modes keep two different pseudos, avoid combining them. */ if (GET_CODE (PATTERN (i3)) == SET) { rtx i3dest = SET_DEST (PATTERN (i3)); while (GET_CODE (i3dest) == SUBREG || GET_CODE (i3dest) == STRICT_LOW_PART || GET_CODE (i3dest) == SIGN_EXTRACT || GET_CODE (i3dest) == ZERO_EXTRACT) i3dest = SUBREG_REG (i3dest); if (SET_SRC (PATTERN (i3)) == i2dest && GET_CODE (i3dest) == REG && ! MODES_TIEABLE_P (GET_MODE (i2dest), GET_MODE (i3dest))) return 0; } /* If I2 contains anything volatile, reject, unless nothing volatile comes between it and I3. */ if (volatile_refs_p (PATTERN (i2))) { rtx insn; for (insn = NEXT_INSN (i2); insn != i3; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) if (volatile_refs_p (PATTERN (insn))) return 0; } /* Likewise for I1; nothing volatile can come between it and I3, except optionally I2. */ if (i1 && volatile_refs_p (PATTERN (i1))) { rtx insn; rtx end = (volatile_refs_p (PATTERN (i2)) ? i2 : i3); for (insn = NEXT_INSN (i1); insn != end; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) if (volatile_refs_p (PATTERN (insn))) return 0; } /* If I1 or I2 contains an autoincrement or autodecrement, make sure that register is not used between there and I3, and not already used in I3 either. Also insist that I3 not be a jump; if it were one and the incremented register were spilled, we would lose. */ for (link = REG_NOTES (i2); link; link = XEXP (link, 1)) if (REG_NOTE_KIND (link) == REG_INC && (GET_CODE (i3) == JUMP_INSN || reg_used_between_p (XEXP (link, 0), i2, i3) || reg_mentioned_p (XEXP (link, 0), PATTERN (i3)))) return 0; if (i1) for (link = REG_NOTES (i1); link; link = XEXP (link, 1)) if (REG_NOTE_KIND (link) == REG_INC && (GET_CODE (i3) == JUMP_INSN || reg_used_between_p (XEXP (link, 0), i1, i3) || reg_mentioned_p (XEXP (link, 0), PATTERN (i3)))) return 0; /* If I3 has an inc, then give up if I1 or I2 uses the reg that is inc'd, EXCEPT in one case: I3 has a post-inc in an output operand. */ if (!(GET_CODE (PATTERN (i3)) == SET && GET_CODE (SET_SRC (PATTERN (i3))) == REG && GET_CODE (SET_DEST (PATTERN (i3))) == MEM && (GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_INC || GET_CODE (XEXP (SET_DEST (PATTERN (i3)), 0)) == POST_DEC))) /* It's not the exception. */ for (link = REG_NOTES (i3); link; link = XEXP (link, 1)) if (REG_NOTE_KIND (link) == REG_INC && (reg_mentioned_p (XEXP (link, 0), PATTERN (i2)) || (i1 != 0 && reg_mentioned_p (XEXP (link, 0), PATTERN (i1))))) return 0; /* Make sure that I1DEST is not used between I2 and I3. */ if (i1 && reg_used_between_p (i1dest, i2, i3)) return 0; /* Don't combine an insn I1 or I2 that follows a CC0-setting insn. An insn that uses CC0 must not be separated from the one that sets it. It would be more logical to test whether CC0 occurs inside I1 or I2, but that would be much slower, and this ought to be equivalent. */ temp = PREV_INSN (i2); while (temp && GET_CODE (temp) == NOTE) temp = PREV_INSN (temp); if (temp && GET_CODE (temp) == INSN && sets_cc0_p (PATTERN (temp))) return 0; if (i1) { temp = PREV_INSN (i2); while (temp && GET_CODE (temp) == NOTE) temp = PREV_INSN (temp); if (temp && GET_CODE (temp) == INSN && sets_cc0_p (PATTERN (temp))) return 0; } /* See if the SETs in i1 or i2 need to be kept around in the merged instruction: whenever the value set there is still needed past i3. */ added_sets_2 = (GET_CODE (i2dest) != CC0 && ! dead_or_set_p (i3, i2dest)); if (i1) added_sets_1 = ! (dead_or_set_p (i3, i1dest) || dead_or_set_p (i2, i1dest)); combine_merges++; undobuf.num_undo = 0; undobuf.storage = 0; /* Substitute in the latest insn for the regs set by the earlier ones. */ maxreg = max_reg_num (); subst_insn = i3; n_occurrences = 0; /* `subst' counts here */ newpat = subst (PATTERN (i3), i2dest, i2src); /* Record whether i2's body now appears within i3's body. */ i2_is_used = n_occurrences; if (i1) { n_occurrences = 0; newpat = subst (newpat, i1dest, i1src); } if (GET_CODE (PATTERN (i3)) == SET && SET_DEST (PATTERN (i3)) == cc0_rtx && (GET_CODE (SET_SRC (PATTERN (i3))) == AND || GET_CODE (SET_SRC (PATTERN (i3))) == LSHIFTRT) && next_insn_tests_no_inequality (i3)) simplify_set_cc0_and (i3); if (max_reg_num () != maxreg) abort (); /* If the actions of the earler insns must be kept in addition to substituting them into the latest one, we must make a new PARALLEL for the latest insn to hold additional the SETs. */ if (added_sets_1 || added_sets_2) { combine_extras++; /* Arrange to free later what we allocate now if we don't accept this combination. */ if (!undobuf.storage) undobuf.storage = (char *) oballoc (0); if (GET_CODE (newpat) == PARALLEL) { rtvec old = XVEC (newpat, 0); total_sets = XVECLEN (newpat, 0) + added_sets_1 + added_sets_2; newpat = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (total_sets)); bcopy (&old->elem[0], &XVECEXP (newpat, 0, 0), sizeof (old->elem[0]) * old->num_elem); } else { rtx old = newpat; total_sets = 1 + added_sets_1 + added_sets_2; newpat = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (total_sets)); XVECEXP (newpat, 0, 0) = old; } if (added_sets_1) { XVECEXP (newpat, 0, --total_sets) = PATTERN (i1); } if (added_sets_2) { /* If there is no I1, use I2's body as is. */ if (i1 == 0 /* If I2 was stuck into I3, then anything within it has already had I1 substituted into it when that was done to I3. */ || i2_is_used) { XVECEXP (newpat, 0, --total_sets) = PATTERN (i2); } else XVECEXP (newpat, 0, --total_sets) = subst (PATTERN (i2), i1dest, i1src); } } /* Fail if an autoincrement side-effect has been duplicated. */ if ((i2_is_used > 1 && find_reg_note (i2, REG_INC, 0) != 0) || (i1 != 0 && n_occurrences > 1 && find_reg_note (i1, REG_INC, 0) != 0)) { undo_all (); return 0; } /* Is the result of combination a valid instruction? */ insn_code_number = recog (newpat, i3); if (insn_code_number >= 0 /* Is the result a reasonable ASM_OPERANDS? */ || (check_asm_operands (newpat) && ! added_sets_1 && ! added_sets_2)) { /* Yes. Install it. */ register int regno; INSN_CODE (i3) = insn_code_number; PATTERN (i3) = newpat; /* If anything was substituted more than once, copy it to avoid invalid shared rtl structure. */ copy_substitutions (); /* The data flowing into I2 now flows into I3. But we cannot always move all of I2's LOG_LINKS into I3, since they must go to a setting of a REG from the first use following. If I2 was the first use following a set, I3 is now a use, but it is not the first use if some instruction between I2 and I3 is also a use. Here, for simplicity, we move all the links only if there are no real insns between I2 and I3. Otherwise, we move only links that correspond to regs that used to die in I2. They are always safe to move. */ add_links (i3, i2, adjacent_insns_p (i2, i3)); /* Most REGs that previously died in I2 now die in I3. */ move_deaths (i2src, INSN_CUID (i2), i3); if (GET_CODE (i2dest) == REG) { /* If the reg formerly set in I2 died only once and that was in I3, zero its use count so it won't make `reload' do any work. */ regno = REGNO (i2dest); if (! added_sets_2) { reg_n_sets[regno]--; /* Used to check && regno_dead_p (regno, i3) also here. */ if (reg_n_sets[regno] == 0 && ! (basic_block_live_at_start[0][regno / HOST_BITS_PER_INT] & (1 << (regno % HOST_BITS_PER_INT)))) reg_n_refs[regno] = 0; } /* If a ref to REGNO was substituted into I3 from I2, then it still dies there if it previously did. Otherwise either REGNO never did die in I3 so remove_death is safe or this entire life of REGNO is gone so remove its death. */ if (!added_sets_2 && ! reg_mentioned_p (i2dest, PATTERN (i3))) remove_death (regno, i3); } /* Any registers previously autoincremented in I2 are now incremented in I3. */ add_incs (i3, REG_NOTES (i2)); if (i1) { /* Likewise, merge the info from I1 and get rid of it. */ add_links (i3, i1, adjacent_insns_p (i1, i2) && adjacent_insns_p (i2, i3)); move_deaths (i1src, INSN_CUID (i1), i3); if (GET_CODE (i1dest) == REG) { regno = REGNO (i1dest); if (! added_sets_1) { reg_n_sets[regno]--; /* Used to also check && regno_dead_p (regno, i3) here. */ if (reg_n_sets[regno] == 0 && ! (basic_block_live_at_start[0][regno / HOST_BITS_PER_INT] & (1 << (regno % HOST_BITS_PER_INT)))) reg_n_refs[regno] = 0; } /* If a ref to REGNO was substituted into I3 from I1, then it still dies there if it previously did. Else either REGNO never did die in I3 so remove_death is safe or this entire life of REGNO is gone so remove its death. */ if (! added_sets_1 && ! reg_mentioned_p (i1dest, PATTERN (i3))) remove_death (regno, i3);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -