X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Frtlanal.c;h=53e6d83d1b8ab03d635c438cccc0e9539ce5bcf9;hb=f67bd9ad79bc7ee36b0245d2f74e1685c3a471b6;hp=d8c9fb8a1bf35756b86352d1d92553641f4c42af;hpb=5ed26a34359b794ffc1b9011818b817b9bcf61f1;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index d8c9fb8a1bf..53e6d83d1b8 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -67,6 +67,22 @@ static int non_rtx_starting_operands[NUM_RTX_CODE]; and set by `-m...' switches. Must be defined in rtlanal.c. */ int target_flags; + +/* Truncation narrows the mode from SOURCE mode to DESTINATION mode. + If TARGET_MODE_REP_EXTENDED (DESTINATION, DESTINATION_REP) is + SIGN_EXTEND then while narrowing we also have to enforce the + representation and sign-extend the value to mode DESTINATION_REP. + + If the value is already sign-extended to DESTINATION_REP mode we + can just switch to DESTINATION mode on it. For each pair of + integral modes SOURCE and DESTINATION, when truncating from SOURCE + to DESTINATION, NUM_SIGN_BIT_COPIES_IN_REP[SOURCE][DESTINATION] + contains the number of high-order bits in SOURCE that have to be + copies of the sign-bit so that we can do this mode-switch to + DESTINATION. */ + +static unsigned int +num_sign_bit_copies_in_rep[MAX_MODE_INT + 1][MAX_MODE_INT + 1]; /* Return 1 if the value of X is unstable (would be different at a different point in the program). @@ -2196,7 +2212,7 @@ may_trap_after_code_motion_p (rtx x) return may_trap_p_1 (x, MTP_AFTER_MOVE); } -/* Same as above, but additionally return non-zero if evaluating rtx X might +/* Same as above, but additionally return nonzero if evaluating rtx X might cause a fault. We define a fault for the purpose of this function as a erroneous execution condition that cannot be encountered during the normal execution of a valid program; the typical example is an unaligned memory @@ -2371,106 +2387,6 @@ replace_rtx (rtx x, rtx from, rtx to) return x; } -/* Throughout the rtx X, replace many registers according to REG_MAP. - Return the replacement for X (which may be X with altered contents). - REG_MAP[R] is the replacement for register R, or 0 for don't replace. - NREGS is the length of REG_MAP; regs >= NREGS are not mapped. - - We only support REG_MAP entries of REG or SUBREG. Also, hard registers - should not be mapped to pseudos or vice versa since validate_change - is not called. - - If REPLACE_DEST is 1, replacements are also done in destinations; - otherwise, only sources are replaced. */ - -rtx -replace_regs (rtx x, rtx *reg_map, unsigned int nregs, int replace_dest) -{ - enum rtx_code code; - int i; - const char *fmt; - - if (x == 0) - return x; - - code = GET_CODE (x); - switch (code) - { - case SCRATCH: - case PC: - case CC0: - case CONST_INT: - case CONST_DOUBLE: - case CONST_VECTOR: - case CONST: - case SYMBOL_REF: - case LABEL_REF: - return x; - - case REG: - /* Verify that the register has an entry before trying to access it. */ - if (REGNO (x) < nregs && reg_map[REGNO (x)] != 0) - { - /* SUBREGs can't be shared. Always return a copy to ensure that if - this replacement occurs more than once then each instance will - get distinct rtx. */ - if (GET_CODE (reg_map[REGNO (x)]) == SUBREG) - return copy_rtx (reg_map[REGNO (x)]); - return reg_map[REGNO (x)]; - } - return x; - - case SUBREG: - /* Prevent making nested SUBREGs. */ - if (REG_P (SUBREG_REG (x)) && REGNO (SUBREG_REG (x)) < nregs - && reg_map[REGNO (SUBREG_REG (x))] != 0 - && GET_CODE (reg_map[REGNO (SUBREG_REG (x))]) == SUBREG) - { - rtx map_val = reg_map[REGNO (SUBREG_REG (x))]; - return simplify_gen_subreg (GET_MODE (x), map_val, - GET_MODE (SUBREG_REG (x)), - SUBREG_BYTE (x)); - } - break; - - case SET: - if (replace_dest) - SET_DEST (x) = replace_regs (SET_DEST (x), reg_map, nregs, 0); - - else if (MEM_P (SET_DEST (x)) - || GET_CODE (SET_DEST (x)) == STRICT_LOW_PART) - /* Even if we are not to replace destinations, replace register if it - is CONTAINED in destination (destination is memory or - STRICT_LOW_PART). */ - XEXP (SET_DEST (x), 0) = replace_regs (XEXP (SET_DEST (x), 0), - reg_map, nregs, 0); - else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT) - /* Similarly, for ZERO_EXTRACT we replace all operands. */ - break; - - SET_SRC (x) = replace_regs (SET_SRC (x), reg_map, nregs, 0); - return x; - - default: - break; - } - - fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - XEXP (x, i) = replace_regs (XEXP (x, i), reg_map, nregs, replace_dest); - else if (fmt[i] == 'E') - { - int j; - for (j = 0; j < XVECLEN (x, i); j++) - XVECEXP (x, i, j) = replace_regs (XVECEXP (x, i, j), reg_map, - nregs, replace_dest); - } - } - return x; -} - /* Replace occurrences of the old label in *X with the new one. DATA is a REPLACE_LABEL_DATA containing the old and new labels. */ @@ -2927,82 +2843,6 @@ auto_inc_p (rtx x) return 0; } -/* Return 1 if the sequence of instructions beginning with FROM and up - to and including TO is safe to move. If NEW_TO is non-NULL, and - the sequence is not already safe to move, but can be easily - extended to a sequence which is safe, then NEW_TO will point to the - end of the extended sequence. - - For now, this function only checks that the region contains whole - exception regions, but it could be extended to check additional - conditions as well. */ - -int -insns_safe_to_move_p (rtx from, rtx to, rtx *new_to) -{ - int eh_region_count = 0; - int past_to_p = 0; - rtx r = from; - - /* By default, assume the end of the region will be what was - suggested. */ - if (new_to) - *new_to = to; - - while (r) - { - if (NOTE_P (r)) - { - switch (NOTE_LINE_NUMBER (r)) - { - case NOTE_INSN_EH_REGION_BEG: - ++eh_region_count; - break; - - case NOTE_INSN_EH_REGION_END: - if (eh_region_count == 0) - /* This sequence of instructions contains the end of - an exception region, but not he beginning. Moving - it will cause chaos. */ - return 0; - - --eh_region_count; - break; - - default: - break; - } - } - else if (past_to_p) - /* If we've passed TO, and we see a non-note instruction, we - can't extend the sequence to a movable sequence. */ - return 0; - - if (r == to) - { - if (!new_to) - /* It's OK to move the sequence if there were matched sets of - exception region notes. */ - return eh_region_count == 0; - - past_to_p = 1; - } - - /* It's OK to move the sequence if there were matched sets of - exception region notes. */ - if (past_to_p && eh_region_count == 0) - { - *new_to = r; - return 1; - } - - /* Go to the next instruction. */ - r = NEXT_INSN (r); - } - - return 0; -} - /* Return nonzero if IN contains a piece of rtl that has the address LOC. */ int loc_mentioned_in_p (rtx *loc, rtx in) @@ -3446,7 +3286,7 @@ rtx_cost (rtx x, enum rtx_code outer_code ATTRIBUTE_UNUSED) total = COSTS_N_INSNS (7); break; case USE: - /* Used in loop.c and combine.c as a marker. */ + /* Used in combine.c as a marker. */ total = 0; break; default: @@ -4808,6 +4648,71 @@ get_condition (rtx jump, rtx *earliest, int allow_cc_mode, int valid_at_insn_p) allow_cc_mode, valid_at_insn_p); } +/* Initialize the table NUM_SIGN_BIT_COPIES_IN_REP based on + TARGET_MODE_REP_EXTENDED. + + Note that we assume that the property of + TARGET_MODE_REP_EXTENDED(B, C) is sticky to the integral modes + narrower than mode B. I.e., if A is a mode narrower than B then in + order to be able to operate on it in mode B, mode A needs to + satisfy the requirements set by the representation of mode B. */ + +static void +init_num_sign_bit_copies_in_rep (void) +{ + enum machine_mode mode, in_mode; + + for (in_mode = GET_CLASS_NARROWEST_MODE (MODE_INT); in_mode != VOIDmode; + in_mode = GET_MODE_WIDER_MODE (mode)) + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != in_mode; + mode = GET_MODE_WIDER_MODE (mode)) + { + enum machine_mode i; + + /* Currently, it is assumed that TARGET_MODE_REP_EXTENDED + extends to the next widest mode. */ + gcc_assert (targetm.mode_rep_extended (mode, in_mode) == UNKNOWN + || GET_MODE_WIDER_MODE (mode) == in_mode); + + /* We are in in_mode. Count how many bits outside of mode + have to be copies of the sign-bit. */ + for (i = mode; i != in_mode; i = GET_MODE_WIDER_MODE (i)) + { + enum machine_mode wider = GET_MODE_WIDER_MODE (i); + + if (targetm.mode_rep_extended (i, wider) == SIGN_EXTEND + /* We can only check sign-bit copies starting from the + top-bit. In order to be able to check the bits we + have already seen we pretend that subsequent bits + have to be sign-bit copies too. */ + || num_sign_bit_copies_in_rep [in_mode][mode]) + num_sign_bit_copies_in_rep [in_mode][mode] + += GET_MODE_BITSIZE (wider) - GET_MODE_BITSIZE (i); + } + } +} + +/* Suppose that truncation from the machine mode of X to MODE is not a + no-op. See if there is anything special about X so that we can + assume it already contains a truncated value of MODE. */ + +bool +truncated_to_mode (enum machine_mode mode, rtx x) +{ + /* This register has already been used in MODE without explicit + truncation. */ + if (REG_P (x) && rtl_hooks.reg_truncated_to_mode (mode, x)) + return true; + + /* See if we already satisfy the requirements of MODE. If yes we + can just switch to MODE. */ + if (num_sign_bit_copies_in_rep[GET_MODE (x)][mode] + && (num_sign_bit_copies (x, GET_MODE (x)) + >= num_sign_bit_copies_in_rep[GET_MODE (x)][mode] + 1)) + return true; + + return false; +} /* Initialize non_rtx_starting_operands, which is used to speed up for_each_rtx. */ @@ -4821,6 +4726,8 @@ init_rtlanal (void) const char *first = strpbrk (format, "eEV"); non_rtx_starting_operands[i] = first ? first - format : -1; } + + init_num_sign_bit_copies_in_rep (); } /* Check whether this is a constant pool constant. */