From: Paolo Bonzini Date: Tue, 25 May 2004 12:04:17 +0000 (+0000) Subject: Makefile.in (OBJS): Add rtlhooks.o. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=2f93eea8612d4ced2eeee52db5ce66bd75303455;p=gcc.git Makefile.in (OBJS): Add rtlhooks.o. 2004-05-25 Paolo Bonzini * Makefile.in (OBJS): Add rtlhooks.o. (rtlanal.o): Depend on function.h. (cse.o): Depend on rtlhooks-def.h. (combine.o): Depend on rtlhooks-def.h. (rtlhooks.o): New rule. * combine.c: Include rtlhooks-def.h. (nonzero_bits, cached_nonzero_bits, nonzero_bits1, num_sign_bit_copies, cached_num_sign_bit_copies, num_sign_bit_copies1): Move most of the code to rtlanal.c. (reg_nonzero_bits_for_combine, reg_num_sign_bit_copies_for_combine): New functions holding the remnants of the above. (combine_rtl_hooks): New. (combine_instructions): Set rtl_hooks instead of gen_lowpart. * cse.c: Include rtlhooks-def.h. (cse_rtl_hooks): New. (cse_main): Set rtl_hooks instead of gen_lowpart. * emit-rtl.c (gen_lowpart): Remove. (gen_lowpart_general): Move to rtlhooks.c. * rtl.h (nonzero_bits, num_sign_bit_copies, struct rtl_hooks, rtl_hooks, general_rtl_hooks): New. (gen_lowpart_general): Remove. (gen_lowpart): Temporarily redefine as a macro. * rtlanal.c: Include function.h. (nonzero_bits, cached_nonzero_bits, nonzero_bits1, num_sign_bit_copies, cached_num_sign_bit_copies, num_sign_bit_copies1): New, from combine.c. * rtlhooks.c: New file. From-SVN: r82234 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c5419232d7b..5248ce15104 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,34 @@ +2004-05-25 Paolo Bonzini + + * Makefile.in (OBJS): Add rtlhooks.o. + (rtlanal.o): Depend on function.h. + (cse.o): Depend on rtlhooks-def.h. + (combine.o): Depend on rtlhooks-def.h. + (rtlhooks.o): New rule. + * combine.c: Include rtlhooks-def.h. + (nonzero_bits, cached_nonzero_bits, nonzero_bits1, + num_sign_bit_copies, cached_num_sign_bit_copies, + num_sign_bit_copies1): Move most of the code to rtlanal.c. + (reg_nonzero_bits_for_combine, + reg_num_sign_bit_copies_for_combine): New functions holding + the remnants of the above. + (combine_rtl_hooks): New. + (combine_instructions): Set rtl_hooks instead of gen_lowpart. + * cse.c: Include rtlhooks-def.h. + (cse_rtl_hooks): New. + (cse_main): Set rtl_hooks instead of gen_lowpart. + * emit-rtl.c (gen_lowpart): Remove. + (gen_lowpart_general): Move to rtlhooks.c. + * rtl.h (nonzero_bits, num_sign_bit_copies, + struct rtl_hooks, rtl_hooks, general_rtl_hooks): New. + (gen_lowpart_general): Remove. + (gen_lowpart): Temporarily redefine as a macro. + * rtlanal.c: Include function.h. + (nonzero_bits, cached_nonzero_bits, nonzero_bits1, + num_sign_bit_copies, cached_num_sign_bit_copies, + num_sign_bit_copies1): New, from combine.c. + * rtlhooks.c: New file. + 2004-05-25 Svein E. Seldal * config/avr/avr.h (LONG_LONG_TYPE_SIZE): Changed long long type diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 63552c5ff8c..568b263a191 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -901,7 +901,7 @@ OBJS-common = \ targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o unroll.o \ varasm.o varray.o version.o vmsdbgout.o xcoffout.o alloc-pool.o \ et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o \ - rtl-profile.o tree-profile.o + rtl-profile.o tree-profile.o rtlhooks.o OBJS-md = $(out_object_file) OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) tree-inline.o \ @@ -1735,7 +1735,7 @@ print-rtl.o : print-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_H) $(TREE_H) hard-reg-set.h $(BASIC_BLOCK_H) real.h $(TM_P_H) rtlanal.o : rtlanal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h \ $(RTL_H) hard-reg-set.h $(TM_P_H) insn-config.h $(RECOG_H) real.h flags.h \ - $(BASIC_BLOCK_H) $(REGS_H) output.h target.h + $(BASIC_BLOCK_H) $(REGS_H) output.h target.h function.h errors.o : errors.c $(CONFIG_H) $(SYSTEM_H) errors.h $(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) @@ -1837,7 +1837,7 @@ cselib.o : cselib.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_ cse.o : cse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \ output.h function.h $(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H) $(TIMEVAR_H) \ - except.h $(TARGET_H) $(PARAMS_H) + except.h $(TARGET_H) $(PARAMS_H) rtlhooks-def.h web.o : web.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ hard-reg-set.h flags.h $(BASIC_BLOCK_H) function.h output.h toplev.h df.h gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ @@ -1938,7 +1938,7 @@ dominance.o : dominance.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ hard-reg-set.h $(BASIC_BLOCK_H) et-forest.h et-forest.o : et-forest.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) et-forest.h alloc-pool.h combine.o : combine.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \ - function.h insn-config.h $(INSN_ATTR_H) $(REGS_H) $(EXPR_H) \ + function.h insn-config.h $(INSN_ATTR_H) $(REGS_H) $(EXPR_H) rtlhooks-def.h \ $(BASIC_BLOCK_H) $(RECOG_H) real.h hard-reg-set.h toplev.h $(TM_P_H) $(TREE_H) $(TARGET_H) regclass.o : regclass.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ hard-reg-set.h flags.h $(BASIC_BLOCK_H) $(REGS_H) insn-config.h $(RECOG_H) reload.h \ @@ -1975,6 +1975,8 @@ reload1.o : reload1.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) real. $(EXPR_H) $(OPTABS_H) reload.h $(REGS_H) hard-reg-set.h insn-config.h \ $(BASIC_BLOCK_H) $(RECOG_H) output.h function.h toplev.h $(TM_P_H) \ except.h $(TREE_H) +rtlhooks.o : rtlhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ + rtlhooks-def.h $(EXPR_H) postreload.o : postreload.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) real.h flags.h \ $(EXPR_H) $(OPTABS_H) reload.h $(REGS_H) hard-reg-set.h insn-config.h \ $(BASIC_BLOCK_H) $(RECOG_H) output.h function.h toplev.h cselib.h $(TM_P_H) \ diff --git a/gcc/combine.c b/gcc/combine.c index 5a1f89bd83d..64af27c779b 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -90,6 +90,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "real.h" #include "toplev.h" #include "target.h" +#include "rtlhooks-def.h" /* Number of attempts to combine instructions in this function. */ @@ -133,12 +134,6 @@ static int max_uid_cuid; #define UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD(val) \ (((unsigned HOST_WIDE_INT) (val) << (BITS_PER_WORD - 1)) << 1) -#define nonzero_bits(X, M) \ - cached_nonzero_bits (X, M, NULL_RTX, VOIDmode, 0) - -#define num_sign_bit_copies(X, M) \ - cached_num_sign_bit_copies (X, M, NULL_RTX, VOIDmode, 0) - /* Maximum register number, which is the size of the tables below. */ static unsigned int combine_max_regno; @@ -337,6 +332,13 @@ static struct undobuf undobuf; static int n_occurrences; +static rtx reg_nonzero_bits_for_combine (rtx, enum machine_mode, rtx, + enum machine_mode, + unsigned HOST_WIDE_INT, + unsigned HOST_WIDE_INT *); +static rtx reg_num_sign_bit_copies_for_combine (rtx, enum machine_mode, rtx, + enum machine_mode, + unsigned int, unsigned int *); static void do_SUBST (rtx *, rtx); static void do_SUBST_INT (int *, int); static void init_reg_last (void); @@ -372,17 +374,6 @@ static rtx make_field_assignment (rtx); static rtx apply_distributive_law (rtx); static rtx simplify_and_const_int (rtx, enum machine_mode, rtx, unsigned HOST_WIDE_INT); -static unsigned HOST_WIDE_INT cached_nonzero_bits (rtx, enum machine_mode, - rtx, enum machine_mode, - unsigned HOST_WIDE_INT); -static unsigned HOST_WIDE_INT nonzero_bits1 (rtx, enum machine_mode, rtx, - enum machine_mode, - unsigned HOST_WIDE_INT); -static unsigned int cached_num_sign_bit_copies (rtx, enum machine_mode, rtx, - enum machine_mode, - unsigned int); -static unsigned int num_sign_bit_copies1 (rtx, enum machine_mode, rtx, - enum machine_mode, unsigned int); static int merge_outer_ops (enum rtx_code *, HOST_WIDE_INT *, enum rtx_code, HOST_WIDE_INT, enum machine_mode, int *); static rtx simplify_shift_const (rtx, enum rtx_code, enum machine_mode, rtx, @@ -412,6 +403,21 @@ static rtx reversed_comparison (rtx, enum machine_mode, rtx, rtx); static enum rtx_code combine_reversed_comparison_code (rtx); static int unmentioned_reg_p_1 (rtx *, void *); static bool unmentioned_reg_p (rtx, rtx); + + +/* It is not safe to use ordinary gen_lowpart in combine. + See comments in gen_lowpart_for_combine. */ +#undef RTL_HOOKS_GEN_LOWPART +#define RTL_HOOKS_GEN_LOWPART gen_lowpart_for_combine + +#undef RTL_HOOKS_REG_NONZERO_REG_BITS +#define RTL_HOOKS_REG_NONZERO_REG_BITS reg_nonzero_bits_for_combine + +#undef RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES +#define RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES reg_num_sign_bit_copies_for_combine + +static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER; + /* Substitute NEWVAL, an rtx expression, into INTO, a place in some insn. The substitution can be undone by undo_all. If INTO is already @@ -522,9 +528,7 @@ combine_instructions (rtx f, unsigned int nregs) combine_max_regno = nregs; - /* It is not safe to use ordinary gen_lowpart in combine. - See comments in gen_lowpart_for_combine. */ - gen_lowpart = gen_lowpart_for_combine; + rtl_hooks = combine_rtl_hooks; reg_stat = xcalloc (nregs, sizeof (struct reg_stat)); @@ -777,7 +781,7 @@ combine_instructions (rtx f, unsigned int nregs) total_successes += combine_successes; nonzero_sign_valid = 0; - gen_lowpart = gen_lowpart_general; + rtl_hooks = general_rtl_hooks; /* Make recognizer allow volatile MEMs again. */ init_recog (); @@ -7997,577 +8001,78 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop, return x; } -#define nonzero_bits_with_known(X, MODE) \ - cached_nonzero_bits (X, MODE, known_x, known_mode, known_ret) - -/* The function cached_nonzero_bits is a wrapper around nonzero_bits1. - It avoids exponential behavior in nonzero_bits1 when X has - identical subexpressions on the first or the second level. */ - -static unsigned HOST_WIDE_INT -cached_nonzero_bits (rtx x, enum machine_mode mode, rtx known_x, - enum machine_mode known_mode, - unsigned HOST_WIDE_INT known_ret) -{ - if (x == known_x && mode == known_mode) - return known_ret; - - /* Try to find identical subexpressions. If found call - nonzero_bits1 on X with the subexpressions as KNOWN_X and the - precomputed value for the subexpression as KNOWN_RET. */ - - if (ARITHMETIC_P (x)) - { - rtx x0 = XEXP (x, 0); - rtx x1 = XEXP (x, 1); - - /* Check the first level. */ - if (x0 == x1) - return nonzero_bits1 (x, mode, x0, mode, - nonzero_bits_with_known (x0, mode)); - - /* Check the second level. */ - if (ARITHMETIC_P (x0) - && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1))) - return nonzero_bits1 (x, mode, x1, mode, - nonzero_bits_with_known (x1, mode)); - - if (ARITHMETIC_P (x1) - && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1))) - return nonzero_bits1 (x, mode, x0, mode, - nonzero_bits_with_known (x0, mode)); - } - - return nonzero_bits1 (x, mode, known_x, known_mode, known_ret); -} - -/* We let num_sign_bit_copies recur into nonzero_bits as that is useful. - We don't let nonzero_bits recur into num_sign_bit_copies, because that - is less useful. We can't allow both, because that results in exponential - run time recursion. There is a nullstone testcase that triggered - this. This macro avoids accidental uses of num_sign_bit_copies. */ -#define cached_num_sign_bit_copies() - -/* Given an expression, X, compute which bits in X can be nonzero. +/* Given a REG, X, compute which bits in X can be nonzero. We don't care about bits outside of those defined in MODE. For most X this is simply GET_MODE_MASK (GET_MODE (MODE)), but if X is a shift, AND, or zero_extract, we can do better. */ -static unsigned HOST_WIDE_INT -nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x, - enum machine_mode known_mode, - unsigned HOST_WIDE_INT known_ret) +static rtx +reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode, + rtx known_x ATTRIBUTE_UNUSED, + enum machine_mode known_mode ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT known_ret ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT *nonzero) { - unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode); - unsigned HOST_WIDE_INT inner_nz; - enum rtx_code code; - unsigned int mode_width = GET_MODE_BITSIZE (mode); rtx tem; - /* For floating-point values, assume all bits are needed. */ - if (FLOAT_MODE_P (GET_MODE (x)) || FLOAT_MODE_P (mode)) - return nonzero; + /* If X is a register whose nonzero bits value is current, use it. + Otherwise, if X is a register whose value we can find, use that + value. Otherwise, use the previously-computed global nonzero bits + for this register. */ - /* If X is wider than MODE, use its mode instead. */ - if (GET_MODE_BITSIZE (GET_MODE (x)) > mode_width) + if (reg_stat[REGNO (x)].last_set_value != 0 + && (reg_stat[REGNO (x)].last_set_mode == mode + || (GET_MODE_CLASS (reg_stat[REGNO (x)].last_set_mode) == MODE_INT + && GET_MODE_CLASS (mode) == MODE_INT)) + && (reg_stat[REGNO (x)].last_set_label == label_tick + || (REGNO (x) >= FIRST_PSEUDO_REGISTER + && REG_N_SETS (REGNO (x)) == 1 + && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, + REGNO (x)))) + && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid) { - mode = GET_MODE (x); - nonzero = GET_MODE_MASK (mode); - mode_width = GET_MODE_BITSIZE (mode); + *nonzero &= reg_stat[REGNO (x)].last_set_nonzero_bits; + return NULL; } - if (mode_width > HOST_BITS_PER_WIDE_INT) - /* Our only callers in this case look for single bit values. So - just return the mode mask. Those tests will then be false. */ - return nonzero; - -#ifndef WORD_REGISTER_OPERATIONS - /* If MODE is wider than X, but both are a single word for both the host - and target machines, we can compute this from which bits of the - object might be nonzero in its own mode, taking into account the fact - that on many CISC machines, accessing an object in a wider mode - causes the high-order bits to become undefined. So they are - not known to be zero. */ - - if (GET_MODE (x) != VOIDmode && GET_MODE (x) != mode - && GET_MODE_BITSIZE (GET_MODE (x)) <= BITS_PER_WORD - && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT - && GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (GET_MODE (x))) - { - nonzero &= nonzero_bits_with_known (x, GET_MODE (x)); - nonzero |= GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x)); - return nonzero; - } -#endif + tem = get_last_value (x); - code = GET_CODE (x); - switch (code) + if (tem) { - case REG: -#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) - /* If pointers extend unsigned and this is a pointer in Pmode, say that - all the bits above ptr_mode are known to be zero. */ - if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode - && REG_POINTER (x)) - nonzero &= GET_MODE_MASK (ptr_mode); -#endif - - /* Include declared information about alignment of pointers. */ - /* ??? We don't properly preserve REG_POINTER changes across - pointer-to-integer casts, so we can't trust it except for - things that we know must be pointers. See execute/960116-1.c. */ - if ((x == stack_pointer_rtx - || x == frame_pointer_rtx - || x == arg_pointer_rtx) - && REGNO_POINTER_ALIGN (REGNO (x))) - { - unsigned HOST_WIDE_INT alignment - = REGNO_POINTER_ALIGN (REGNO (x)) / BITS_PER_UNIT; - -#ifdef PUSH_ROUNDING - /* If PUSH_ROUNDING is defined, it is possible for the - stack to be momentarily aligned only to that amount, - so we pick the least alignment. */ - if (x == stack_pointer_rtx && PUSH_ARGS) - alignment = MIN ((unsigned HOST_WIDE_INT) PUSH_ROUNDING (1), - alignment); -#endif - - nonzero &= ~(alignment - 1); - } - - /* If X is a register whose nonzero bits value is current, use it. - Otherwise, if X is a register whose value we can find, use that - value. Otherwise, use the previously-computed global nonzero bits - for this register. */ - - if (reg_stat[REGNO (x)].last_set_value != 0 - && (reg_stat[REGNO (x)].last_set_mode == mode - || (GET_MODE_CLASS (reg_stat[REGNO (x)].last_set_mode) == MODE_INT - && GET_MODE_CLASS (mode) == MODE_INT)) - && (reg_stat[REGNO (x)].last_set_label == label_tick - || (REGNO (x) >= FIRST_PSEUDO_REGISTER - && REG_N_SETS (REGNO (x)) == 1 - && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, - REGNO (x)))) - && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid) - return reg_stat[REGNO (x)].last_set_nonzero_bits & nonzero; - - tem = get_last_value (x); - - if (tem) - { -#ifdef SHORT_IMMEDIATES_SIGN_EXTEND - /* If X is narrower than MODE and TEM is a non-negative - constant that would appear negative in the mode of X, - sign-extend it for use in reg_stat[].nonzero_bits because - some machines (maybe most) will actually do the sign-extension - and this is the conservative approach. - - ??? For 2.5, try to tighten up the MD files in this regard - instead of this kludge. */ - - if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width - && GET_CODE (tem) == CONST_INT - && INTVAL (tem) > 0 - && 0 != (INTVAL (tem) - & ((HOST_WIDE_INT) 1 - << (GET_MODE_BITSIZE (GET_MODE (x)) - 1)))) - tem = GEN_INT (INTVAL (tem) - | ((HOST_WIDE_INT) (-1) - << GET_MODE_BITSIZE (GET_MODE (x)))); -#endif - return nonzero_bits_with_known (tem, mode) & nonzero; - } - else if (nonzero_sign_valid && reg_stat[REGNO (x)].nonzero_bits) - { - unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits; - - if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width) - /* We don't know anything about the upper bits. */ - mask |= GET_MODE_MASK (mode) ^ GET_MODE_MASK (GET_MODE (x)); - return nonzero & mask; - } - else - return nonzero; - - case CONST_INT: #ifdef SHORT_IMMEDIATES_SIGN_EXTEND - /* If X is negative in MODE, sign-extend the value. */ - if (INTVAL (x) > 0 && mode_width < BITS_PER_WORD - && 0 != (INTVAL (x) & ((HOST_WIDE_INT) 1 << (mode_width - 1)))) - return (INTVAL (x) | ((HOST_WIDE_INT) (-1) << mode_width)); -#endif - - return INTVAL (x); - - case MEM: -#ifdef LOAD_EXTEND_OP - /* In many, if not most, RISC machines, reading a byte from memory - zeros the rest of the register. Noticing that fact saves a lot - of extra zero-extends. */ - if (LOAD_EXTEND_OP (GET_MODE (x)) == ZERO_EXTEND) - nonzero &= GET_MODE_MASK (GET_MODE (x)); -#endif - break; - - case EQ: case NE: - case UNEQ: case LTGT: - case GT: case GTU: case UNGT: - case LT: case LTU: case UNLT: - case GE: case GEU: case UNGE: - case LE: case LEU: case UNLE: - case UNORDERED: case ORDERED: - - /* If this produces an integer result, we know which bits are set. - Code here used to clear bits outside the mode of X, but that is - now done above. */ - - if (GET_MODE_CLASS (mode) == MODE_INT - && mode_width <= HOST_BITS_PER_WIDE_INT) - nonzero = STORE_FLAG_VALUE; - break; - - case NEG: -#if 0 - /* Disabled to avoid exponential mutual recursion between nonzero_bits - and num_sign_bit_copies. */ - if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x)) - == GET_MODE_BITSIZE (GET_MODE (x))) - nonzero = 1; -#endif - - if (GET_MODE_SIZE (GET_MODE (x)) < mode_width) - nonzero |= (GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x))); - break; - - case ABS: -#if 0 - /* Disabled to avoid exponential mutual recursion between nonzero_bits - and num_sign_bit_copies. */ - if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x)) - == GET_MODE_BITSIZE (GET_MODE (x))) - nonzero = 1; -#endif - break; - - case TRUNCATE: - nonzero &= (nonzero_bits_with_known (XEXP (x, 0), mode) - & GET_MODE_MASK (mode)); - break; - - case ZERO_EXTEND: - nonzero &= nonzero_bits_with_known (XEXP (x, 0), mode); - if (GET_MODE (XEXP (x, 0)) != VOIDmode) - nonzero &= GET_MODE_MASK (GET_MODE (XEXP (x, 0))); - break; - - case SIGN_EXTEND: - /* If the sign bit is known clear, this is the same as ZERO_EXTEND. - Otherwise, show all the bits in the outer mode but not the inner - may be nonzero. */ - inner_nz = nonzero_bits_with_known (XEXP (x, 0), mode); - if (GET_MODE (XEXP (x, 0)) != VOIDmode) - { - inner_nz &= GET_MODE_MASK (GET_MODE (XEXP (x, 0))); - if (inner_nz - & (((HOST_WIDE_INT) 1 - << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1)))) - inner_nz |= (GET_MODE_MASK (mode) - & ~GET_MODE_MASK (GET_MODE (XEXP (x, 0)))); - } - - nonzero &= inner_nz; - break; - - case AND: - nonzero &= (nonzero_bits_with_known (XEXP (x, 0), mode) - & nonzero_bits_with_known (XEXP (x, 1), mode)); - break; - - case XOR: case IOR: - case UMIN: case UMAX: case SMIN: case SMAX: - { - unsigned HOST_WIDE_INT nonzero0 = - nonzero_bits_with_known (XEXP (x, 0), mode); - - /* Don't call nonzero_bits for the second time if it cannot change - anything. */ - if ((nonzero & nonzero0) != nonzero) - nonzero &= (nonzero0 - | nonzero_bits_with_known (XEXP (x, 1), mode)); - } - break; - - case PLUS: case MINUS: - case MULT: - case DIV: case UDIV: - case MOD: case UMOD: - /* We can apply the rules of arithmetic to compute the number of - high- and low-order zero bits of these operations. We start by - computing the width (position of the highest-order nonzero bit) - and the number of low-order zero bits for each value. */ - { - unsigned HOST_WIDE_INT nz0 = - nonzero_bits_with_known (XEXP (x, 0), mode); - unsigned HOST_WIDE_INT nz1 = - nonzero_bits_with_known (XEXP (x, 1), mode); - int sign_index = GET_MODE_BITSIZE (GET_MODE (x)) - 1; - int width0 = floor_log2 (nz0) + 1; - int width1 = floor_log2 (nz1) + 1; - int low0 = floor_log2 (nz0 & -nz0); - int low1 = floor_log2 (nz1 & -nz1); - HOST_WIDE_INT op0_maybe_minusp - = (nz0 & ((HOST_WIDE_INT) 1 << sign_index)); - HOST_WIDE_INT op1_maybe_minusp - = (nz1 & ((HOST_WIDE_INT) 1 << sign_index)); - unsigned int result_width = mode_width; - int result_low = 0; - - switch (code) - { - case PLUS: - result_width = MAX (width0, width1) + 1; - result_low = MIN (low0, low1); - break; - case MINUS: - result_low = MIN (low0, low1); - break; - case MULT: - result_width = width0 + width1; - result_low = low0 + low1; - break; - case DIV: - if (width1 == 0) - break; - if (! op0_maybe_minusp && ! op1_maybe_minusp) - result_width = width0; - break; - case UDIV: - if (width1 == 0) - break; - result_width = width0; - break; - case MOD: - if (width1 == 0) - break; - if (! op0_maybe_minusp && ! op1_maybe_minusp) - result_width = MIN (width0, width1); - result_low = MIN (low0, low1); - break; - case UMOD: - if (width1 == 0) - break; - result_width = MIN (width0, width1); - result_low = MIN (low0, low1); - break; - default: - abort (); - } - - if (result_width < mode_width) - nonzero &= ((HOST_WIDE_INT) 1 << result_width) - 1; - - if (result_low > 0) - nonzero &= ~(((HOST_WIDE_INT) 1 << result_low) - 1); - -#ifdef POINTERS_EXTEND_UNSIGNED - /* If pointers extend unsigned and this is an addition or subtraction - to a pointer in Pmode, all the bits above ptr_mode are known to be - zero. */ - if (POINTERS_EXTEND_UNSIGNED > 0 && GET_MODE (x) == Pmode - && (code == PLUS || code == MINUS) - && GET_CODE (XEXP (x, 0)) == REG && REG_POINTER (XEXP (x, 0))) - nonzero &= GET_MODE_MASK (ptr_mode); -#endif - } - break; - - case ZERO_EXTRACT: - if (GET_CODE (XEXP (x, 1)) == CONST_INT - && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT) - nonzero &= ((HOST_WIDE_INT) 1 << INTVAL (XEXP (x, 1))) - 1; - break; - - case SUBREG: - /* If this is a SUBREG formed for a promoted variable that has - been zero-extended, we know that at least the high-order bits - are zero, though others might be too. */ - - if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x) > 0) - nonzero = (GET_MODE_MASK (GET_MODE (x)) - & nonzero_bits_with_known (SUBREG_REG (x), GET_MODE (x))); - - /* If the inner mode is a single word for both the host and target - machines, we can compute this from which bits of the inner - object might be nonzero. */ - if (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) <= BITS_PER_WORD - && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - <= HOST_BITS_PER_WIDE_INT)) - { - nonzero &= nonzero_bits_with_known (SUBREG_REG (x), mode); - -#if defined (WORD_REGISTER_OPERATIONS) && defined (LOAD_EXTEND_OP) - /* If this is a typical RISC machine, we only have to worry - about the way loads are extended. */ - if ((LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND - ? (((nonzero - & (((unsigned HOST_WIDE_INT) 1 - << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1)))) - != 0)) - : LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) != ZERO_EXTEND) - || GET_CODE (SUBREG_REG (x)) != MEM) + /* If X is narrower than MODE and TEM is a non-negative + constant that would appear negative in the mode of X, + sign-extend it for use in reg_nonzero_bits because some + machines (maybe most) will actually do the sign-extension + and this is the conservative approach. + + ??? For 2.5, try to tighten up the MD files in this regard + instead of this kludge. */ + + if (GET_MODE_BITSIZE (GET_MODE (x)) < GET_MODE_BITSIZE (mode) + && GET_CODE (tem) == CONST_INT + && INTVAL (tem) > 0 + && 0 != (INTVAL (tem) + & ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (GET_MODE (x)) - 1)))) + tem = GEN_INT (INTVAL (tem) + | ((HOST_WIDE_INT) (-1) + << GET_MODE_BITSIZE (GET_MODE (x)))); #endif - { - /* On many CISC machines, accessing an object in a wider mode - causes the high-order bits to become undefined. So they are - not known to be zero. */ - if (GET_MODE_SIZE (GET_MODE (x)) - > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) - nonzero |= (GET_MODE_MASK (GET_MODE (x)) - & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))); - } - } - break; - - case ASHIFTRT: - case LSHIFTRT: - case ASHIFT: - case ROTATE: - /* The nonzero bits are in two classes: any bits within MODE - that aren't in GET_MODE (x) are always significant. The rest of the - nonzero bits are those that are significant in the operand of - the shift when shifted the appropriate number of bits. This - shows that high-order bits are cleared by the right shift and - low-order bits by left shifts. */ - if (GET_CODE (XEXP (x, 1)) == CONST_INT - && INTVAL (XEXP (x, 1)) >= 0 - && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT) - { - enum machine_mode inner_mode = GET_MODE (x); - unsigned int width = GET_MODE_BITSIZE (inner_mode); - int count = INTVAL (XEXP (x, 1)); - unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (inner_mode); - unsigned HOST_WIDE_INT op_nonzero = - nonzero_bits_with_known (XEXP (x, 0), mode); - unsigned HOST_WIDE_INT inner = op_nonzero & mode_mask; - unsigned HOST_WIDE_INT outer = 0; - - if (mode_width > width) - outer = (op_nonzero & nonzero & ~mode_mask); - - if (code == LSHIFTRT) - inner >>= count; - else if (code == ASHIFTRT) - { - inner >>= count; - - /* If the sign bit may have been nonzero before the shift, we - need to mark all the places it could have been copied to - by the shift as possibly nonzero. */ - if (inner & ((HOST_WIDE_INT) 1 << (width - 1 - count))) - inner |= (((HOST_WIDE_INT) 1 << count) - 1) << (width - count); - } - else if (code == ASHIFT) - inner <<= count; - else - inner = ((inner << (count % width) - | (inner >> (width - (count % width)))) & mode_mask); - - nonzero &= (outer | inner); - } - break; - - case FFS: - case POPCOUNT: - /* This is at most the number of bits in the mode. */ - nonzero = ((HOST_WIDE_INT) 2 << (floor_log2 (mode_width))) - 1; - break; - - case CLZ: - /* If CLZ has a known value at zero, then the nonzero bits are - that value, plus the number of bits in the mode minus one. */ - if (CLZ_DEFINED_VALUE_AT_ZERO (mode, nonzero)) - nonzero |= ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1; - else - nonzero = -1; - break; - - case CTZ: - /* If CTZ has a known value at zero, then the nonzero bits are - that value, plus the number of bits in the mode minus one. */ - if (CTZ_DEFINED_VALUE_AT_ZERO (mode, nonzero)) - nonzero |= ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1; - else - nonzero = -1; - break; - - case PARITY: - nonzero = 1; - break; - - case IF_THEN_ELSE: - nonzero &= (nonzero_bits_with_known (XEXP (x, 1), mode) - | nonzero_bits_with_known (XEXP (x, 2), mode)); - break; - - default: - break; + return tem; } - - return nonzero; -} - -/* See the macro definition above. */ -#undef cached_num_sign_bit_copies - -#define num_sign_bit_copies_with_known(X, M) \ - cached_num_sign_bit_copies (X, M, known_x, known_mode, known_ret) - -/* The function cached_num_sign_bit_copies is a wrapper around - num_sign_bit_copies1. It avoids exponential behavior in - num_sign_bit_copies1 when X has identical subexpressions on the - first or the second level. */ - -static unsigned int -cached_num_sign_bit_copies (rtx x, enum machine_mode mode, rtx known_x, - enum machine_mode known_mode, - unsigned int known_ret) -{ - if (x == known_x && mode == known_mode) - return known_ret; - - /* Try to find identical subexpressions. If found call - num_sign_bit_copies1 on X with the subexpressions as KNOWN_X and - the precomputed value for the subexpression as KNOWN_RET. */ - - if (ARITHMETIC_P (x)) + else if (nonzero_sign_valid && reg_stat[REGNO (x)].nonzero_bits) { - rtx x0 = XEXP (x, 0); - rtx x1 = XEXP (x, 1); - - /* Check the first level. */ - if (x0 == x1) - return - num_sign_bit_copies1 (x, mode, x0, mode, - num_sign_bit_copies_with_known (x0, mode)); - - /* Check the second level. */ - if (ARITHMETIC_P (x0) - && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1))) - return - num_sign_bit_copies1 (x, mode, x1, mode, - num_sign_bit_copies_with_known (x1, mode)); + unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits; - if (ARITHMETIC_P (x1) - && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1))) - return - num_sign_bit_copies1 (x, mode, x0, mode, - num_sign_bit_copies_with_known (x0, mode)); + if (GET_MODE_BITSIZE (GET_MODE (x)) < GET_MODE_BITSIZE (mode)) + /* We don't know anything about the upper bits. */ + mask |= GET_MODE_MASK (mode) ^ GET_MODE_MASK (GET_MODE (x)); + *nonzero &= mask; } - return num_sign_bit_copies1 (x, mode, known_x, known_mode, known_ret); + return NULL; } /* Return the number of bits at the high-order end of X that are known to @@ -8575,354 +8080,38 @@ cached_num_sign_bit_copies (rtx x, enum machine_mode mode, rtx known_x, VOIDmode, X will be used in its own mode. The returned value will always be between 1 and the number of bits in MODE. */ -static unsigned int -num_sign_bit_copies1 (rtx x, enum machine_mode mode, rtx known_x, - enum machine_mode known_mode, - unsigned int known_ret) +static rtx +reg_num_sign_bit_copies_for_combine (rtx x, enum machine_mode mode, + rtx known_x ATTRIBUTE_UNUSED, + enum machine_mode known_mode + ATTRIBUTE_UNUSED, + unsigned int known_ret ATTRIBUTE_UNUSED, + unsigned int *result) { - enum rtx_code code = GET_CODE (x); - unsigned int bitwidth; - int num0, num1, result; - unsigned HOST_WIDE_INT nonzero; rtx tem; - /* If we weren't given a mode, use the mode of X. If the mode is still - VOIDmode, we don't know anything. Likewise if one of the modes is - floating-point. */ - - if (mode == VOIDmode) - mode = GET_MODE (x); - - if (mode == VOIDmode || FLOAT_MODE_P (mode) || FLOAT_MODE_P (GET_MODE (x))) - return 1; - - bitwidth = GET_MODE_BITSIZE (mode); - - /* For a smaller object, just ignore the high bits. */ - if (bitwidth < GET_MODE_BITSIZE (GET_MODE (x))) + if (reg_stat[REGNO (x)].last_set_value != 0 + && reg_stat[REGNO (x)].last_set_mode == mode + && (reg_stat[REGNO (x)].last_set_label == label_tick + || (REGNO (x) >= FIRST_PSEUDO_REGISTER + && REG_N_SETS (REGNO (x)) == 1 + && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, + REGNO (x)))) + && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid) { - num0 = num_sign_bit_copies_with_known (x, GET_MODE (x)); - return MAX (1, - num0 - (int) (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth)); - } - - if (GET_MODE (x) != VOIDmode && bitwidth > GET_MODE_BITSIZE (GET_MODE (x))) - { -#ifndef WORD_REGISTER_OPERATIONS - /* If this machine does not do all register operations on the entire - register and MODE is wider than the mode of X, we can say nothing - at all about the high-order bits. */ - return 1; -#else - /* Likewise on machines that do, if the mode of the object is smaller - than a word and loads of that size don't sign extend, we can say - nothing about the high order bits. */ - if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD -#ifdef LOAD_EXTEND_OP - && LOAD_EXTEND_OP (GET_MODE (x)) != SIGN_EXTEND -#endif - ) - return 1; -#endif + *result = reg_stat[REGNO (x)].last_set_sign_bit_copies; + return NULL; } - switch (code) - { - case REG: + tem = get_last_value (x); + if (tem != 0) + return tem; -#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) - /* If pointers extend signed and this is a pointer in Pmode, say that - all the bits above ptr_mode are known to be sign bit copies. */ - if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && mode == Pmode - && REG_POINTER (x)) - return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1; -#endif - - if (reg_stat[REGNO (x)].last_set_value != 0 - && reg_stat[REGNO (x)].last_set_mode == mode - && (reg_stat[REGNO (x)].last_set_label == label_tick - || (REGNO (x) >= FIRST_PSEUDO_REGISTER - && REG_N_SETS (REGNO (x)) == 1 - && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, - REGNO (x)))) - && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid) - return reg_stat[REGNO (x)].last_set_sign_bit_copies; - - tem = get_last_value (x); - if (tem != 0) - return num_sign_bit_copies_with_known (tem, mode); - - if (nonzero_sign_valid && reg_stat[REGNO (x)].sign_bit_copies != 0 - && GET_MODE_BITSIZE (GET_MODE (x)) == bitwidth) - return reg_stat[REGNO (x)].sign_bit_copies; - break; - - case MEM: -#ifdef LOAD_EXTEND_OP - /* Some RISC machines sign-extend all loads of smaller than a word. */ - if (LOAD_EXTEND_OP (GET_MODE (x)) == SIGN_EXTEND) - return MAX (1, ((int) bitwidth - - (int) GET_MODE_BITSIZE (GET_MODE (x)) + 1)); -#endif - break; - - case CONST_INT: - /* If the constant is negative, take its 1's complement and remask. - Then see how many zero bits we have. */ - nonzero = INTVAL (x) & GET_MODE_MASK (mode); - if (bitwidth <= HOST_BITS_PER_WIDE_INT - && (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0) - nonzero = (~nonzero) & GET_MODE_MASK (mode); - - return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1); - - case SUBREG: - /* If this is a SUBREG for a promoted object that is sign-extended - and we are looking at it in a wider mode, we know that at least the - high-order bits are known to be sign bit copies. */ - - if (SUBREG_PROMOTED_VAR_P (x) && ! SUBREG_PROMOTED_UNSIGNED_P (x)) - { - num0 = num_sign_bit_copies_with_known (SUBREG_REG (x), mode); - return MAX ((int) bitwidth - - (int) GET_MODE_BITSIZE (GET_MODE (x)) + 1, - num0); - } - - /* For a smaller object, just ignore the high bits. */ - if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))) - { - num0 = num_sign_bit_copies_with_known (SUBREG_REG (x), VOIDmode); - return MAX (1, (num0 - - (int) (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - - bitwidth))); - } - -#ifdef WORD_REGISTER_OPERATIONS -#ifdef LOAD_EXTEND_OP - /* For paradoxical SUBREGs on machines where all register operations - affect the entire register, just look inside. Note that we are - passing MODE to the recursive call, so the number of sign bit copies - will remain relative to that mode, not the inner mode. */ - - /* This works only if loads sign extend. Otherwise, if we get a - reload for the inner part, it may be loaded from the stack, and - then we lose all sign bit copies that existed before the store - to the stack. */ - - if ((GET_MODE_SIZE (GET_MODE (x)) - > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) - && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND - && GET_CODE (SUBREG_REG (x)) == MEM) - return num_sign_bit_copies_with_known (SUBREG_REG (x), mode); -#endif -#endif - break; - - case SIGN_EXTRACT: - if (GET_CODE (XEXP (x, 1)) == CONST_INT) - return MAX (1, (int) bitwidth - INTVAL (XEXP (x, 1))); - break; - - case SIGN_EXTEND: - return (bitwidth - GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - + num_sign_bit_copies_with_known (XEXP (x, 0), VOIDmode)); - - case TRUNCATE: - /* For a smaller object, just ignore the high bits. */ - num0 = num_sign_bit_copies_with_known (XEXP (x, 0), VOIDmode); - return MAX (1, (num0 - (int) (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - - bitwidth))); - - case NOT: - return num_sign_bit_copies_with_known (XEXP (x, 0), mode); - - case ROTATE: case ROTATERT: - /* If we are rotating left by a number of bits less than the number - of sign bit copies, we can just subtract that amount from the - number. */ - if (GET_CODE (XEXP (x, 1)) == CONST_INT - && INTVAL (XEXP (x, 1)) >= 0 - && INTVAL (XEXP (x, 1)) < (int) bitwidth) - { - num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode); - return MAX (1, num0 - (code == ROTATE ? INTVAL (XEXP (x, 1)) - : (int) bitwidth - INTVAL (XEXP (x, 1)))); - } - break; - - case NEG: - /* In general, this subtracts one sign bit copy. But if the value - is known to be positive, the number of sign bit copies is the - same as that of the input. Finally, if the input has just one bit - that might be nonzero, all the bits are copies of the sign bit. */ - num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode); - if (bitwidth > HOST_BITS_PER_WIDE_INT) - return num0 > 1 ? num0 - 1 : 1; - - nonzero = nonzero_bits (XEXP (x, 0), mode); - if (nonzero == 1) - return bitwidth; - - if (num0 > 1 - && (((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero)) - num0--; - - return num0; - - case IOR: case AND: case XOR: - case SMIN: case SMAX: case UMIN: case UMAX: - /* Logical operations will preserve the number of sign-bit copies. - MIN and MAX operations always return one of the operands. */ - num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode); - num1 = num_sign_bit_copies_with_known (XEXP (x, 1), mode); - return MIN (num0, num1); - - case PLUS: case MINUS: - /* For addition and subtraction, we can have a 1-bit carry. However, - if we are subtracting 1 from a positive number, there will not - be such a carry. Furthermore, if the positive number is known to - be 0 or 1, we know the result is either -1 or 0. */ - - if (code == PLUS && XEXP (x, 1) == constm1_rtx - && bitwidth <= HOST_BITS_PER_WIDE_INT) - { - nonzero = nonzero_bits (XEXP (x, 0), mode); - if ((((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero) == 0) - return (nonzero == 1 || nonzero == 0 ? bitwidth - : bitwidth - floor_log2 (nonzero) - 1); - } - - num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode); - num1 = num_sign_bit_copies_with_known (XEXP (x, 1), mode); - result = MAX (1, MIN (num0, num1) - 1); - -#ifdef POINTERS_EXTEND_UNSIGNED - /* If pointers extend signed and this is an addition or subtraction - to a pointer in Pmode, all the bits above ptr_mode are known to be - sign bit copies. */ - if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode - && (code == PLUS || code == MINUS) - && GET_CODE (XEXP (x, 0)) == REG && REG_POINTER (XEXP (x, 0))) - result = MAX ((int) (GET_MODE_BITSIZE (Pmode) - - GET_MODE_BITSIZE (ptr_mode) + 1), - result); -#endif - return result; - - case MULT: - /* The number of bits of the product is the sum of the number of - bits of both terms. However, unless one of the terms if known - to be positive, we must allow for an additional bit since negating - a negative number can remove one sign bit copy. */ - - num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode); - num1 = num_sign_bit_copies_with_known (XEXP (x, 1), mode); - - result = bitwidth - (bitwidth - num0) - (bitwidth - num1); - if (result > 0 - && (bitwidth > HOST_BITS_PER_WIDE_INT - || (((nonzero_bits (XEXP (x, 0), mode) - & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0) - && ((nonzero_bits (XEXP (x, 1), mode) - & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)))) - result--; - - return MAX (1, result); - - case UDIV: - /* The result must be <= the first operand. If the first operand - has the high bit set, we know nothing about the number of sign - bit copies. */ - if (bitwidth > HOST_BITS_PER_WIDE_INT) - return 1; - else if ((nonzero_bits (XEXP (x, 0), mode) - & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0) - return 1; - else - return num_sign_bit_copies_with_known (XEXP (x, 0), mode); - - case UMOD: - /* The result must be <= the second operand. */ - return num_sign_bit_copies_with_known (XEXP (x, 1), mode); - - case DIV: - /* Similar to unsigned division, except that we have to worry about - the case where the divisor is negative, in which case we have - to add 1. */ - result = num_sign_bit_copies_with_known (XEXP (x, 0), mode); - if (result > 1 - && (bitwidth > HOST_BITS_PER_WIDE_INT - || (nonzero_bits (XEXP (x, 1), mode) - & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)) - result--; - - return result; - - case MOD: - result = num_sign_bit_copies_with_known (XEXP (x, 1), mode); - if (result > 1 - && (bitwidth > HOST_BITS_PER_WIDE_INT - || (nonzero_bits (XEXP (x, 1), mode) - & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)) - result--; - - return result; - - case ASHIFTRT: - /* Shifts by a constant add to the number of bits equal to the - sign bit. */ - num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode); - if (GET_CODE (XEXP (x, 1)) == CONST_INT - && INTVAL (XEXP (x, 1)) > 0) - num0 = MIN ((int) bitwidth, num0 + INTVAL (XEXP (x, 1))); - - return num0; - - case ASHIFT: - /* Left shifts destroy copies. */ - if (GET_CODE (XEXP (x, 1)) != CONST_INT - || INTVAL (XEXP (x, 1)) < 0 - || INTVAL (XEXP (x, 1)) >= (int) bitwidth) - return 1; - - num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode); - return MAX (1, num0 - INTVAL (XEXP (x, 1))); - - case IF_THEN_ELSE: - num0 = num_sign_bit_copies_with_known (XEXP (x, 1), mode); - num1 = num_sign_bit_copies_with_known (XEXP (x, 2), mode); - return MIN (num0, num1); - - case EQ: case NE: case GE: case GT: case LE: case LT: - case UNEQ: case LTGT: case UNGE: case UNGT: case UNLE: case UNLT: - case GEU: case GTU: case LEU: case LTU: - case UNORDERED: case ORDERED: - /* If the constant is negative, take its 1's complement and remask. - Then see how many zero bits we have. */ - nonzero = STORE_FLAG_VALUE; - if (bitwidth <= HOST_BITS_PER_WIDE_INT - && (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0) - nonzero = (~nonzero) & GET_MODE_MASK (mode); - - return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1); - break; - - default: - break; - } - - /* If we haven't been able to figure it out by one of the above rules, - see if some of the high-order bits are known to be zero. If so, - count those bits and return one less than that amount. If we can't - safely compute the mask for this mode, always return BITWIDTH. */ - - if (bitwidth > HOST_BITS_PER_WIDE_INT) - return 1; - - nonzero = nonzero_bits (x, mode); - return (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1)) - ? 1 : bitwidth - floor_log2 (nonzero) - 1); + if (nonzero_sign_valid && reg_stat[REGNO (x)].sign_bit_copies != 0 + && GET_MODE_BITSIZE (GET_MODE (x)) == GET_MODE_BITSIZE (mode)) + *result = reg_stat[REGNO (x)].sign_bit_copies; + + return NULL; } /* Return the number of "extended" bits there are in X, when interpreted diff --git a/gcc/cse.c b/gcc/cse.c index 6d3c53f7635..5f1107c3e22 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -43,6 +43,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "except.h" #include "target.h" #include "params.h" +#include "rtlhooks-def.h" /* The basic idea of common subexpression elimination is to go through the code, keeping a record of expressions that would @@ -664,6 +665,12 @@ static int cse_change_cc_mode (rtx *, void *); static void cse_change_cc_mode_insns (rtx, rtx, rtx); static enum machine_mode cse_cc_succs (basic_block, rtx, rtx, bool); + +#undef RTL_HOOKS_GEN_LOWPART +#define RTL_HOOKS_GEN_LOWPART gen_lowpart_if_possible + +static const struct rtl_hooks cse_rtl_hooks = RTL_HOOKS_INITIALIZER; + /* Nonzero if X has the form (PLUS frame-pointer integer). We check for virtual regs here because the simplify_*_operation routines are called by integrate.c, which is called before virtual register instantiation. */ @@ -6881,7 +6888,7 @@ cse_main (rtx f, int nregs, int after_loop, FILE *file) constant_pool_entries_cost = 0; constant_pool_entries_regcost = 0; val.path_size = 0; - gen_lowpart = gen_lowpart_if_possible; + rtl_hooks = cse_rtl_hooks; init_recog (); init_alias_analysis (); @@ -7001,7 +7008,7 @@ cse_main (rtx f, int nregs, int after_loop, FILE *file) free (uid_cuid); free (reg_eqv_table); free (val.path); - gen_lowpart = gen_lowpart_general; + rtl_hooks = general_rtl_hooks; return cse_jumps_altered || recorded_label_ref; } diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index ba8a3d6cf24..9211c087537 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -97,8 +97,6 @@ rtx global_rtl[GR_MAX]; at the beginning of each function. */ static GTY(()) rtx static_regno_reg_rtx[FIRST_PSEUDO_REGISTER]; -rtx (*gen_lowpart) (enum machine_mode mode, rtx x) = gen_lowpart_general; - /* We record floating-point CONST_DOUBLEs in each floating-point mode for the values of 0, 1, and 2. For the integer entries and VOIDmode, we record a copy of const[012]_rtx. */ @@ -1124,62 +1122,6 @@ gen_imagpart (enum machine_mode mode, rtx x) return gen_highpart (mode, x); } -/* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a value, - return an rtx (MEM, SUBREG, or CONST_INT) that refers to the - least-significant part of X. - MODE specifies how big a part of X to return; - it usually should not be larger than a word. - If X is a MEM whose address is a QUEUED, the value may be so also. */ - -rtx -gen_lowpart_general (enum machine_mode mode, rtx x) -{ - rtx result = gen_lowpart_common (mode, x); - - if (result) - return result; - else if (GET_CODE (x) == REG) - { - /* Must be a hard reg that's not valid in MODE. */ - result = gen_lowpart_common (mode, copy_to_reg (x)); - if (result == 0) - abort (); - return result; - } - else if (GET_CODE (x) == MEM) - { - /* The only additional case we can do is MEM. */ - int offset = 0; - - /* The following exposes the use of "x" to CSE. */ - if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD - && SCALAR_INT_MODE_P (GET_MODE (x)) - && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), - GET_MODE_BITSIZE (GET_MODE (x))) - && ! no_new_pseudos) - return gen_lowpart (mode, force_reg (GET_MODE (x), x)); - - if (WORDS_BIG_ENDIAN) - offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) - - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)); - - if (BYTES_BIG_ENDIAN) - /* Adjust the address so that the address-after-the-data - is unchanged. */ - offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)) - - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); - - return adjust_address (x, mode, offset); - } - else if (GET_CODE (x) == ADDRESSOF) - return gen_lowpart (mode, force_reg (GET_MODE (x), x)); - else - abort (); -} - -/* Like `gen_lowpart', but refer to the most significant part. - This is used to access the imaginary part of a complex number. */ - rtx gen_highpart (enum machine_mode mode, rtx x) { diff --git a/gcc/rtl.h b/gcc/rtl.h index cb6850a9927..65f68d81b59 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1195,6 +1195,9 @@ extern unsigned int subreg_regno_offset (unsigned int, enum machine_mode, extern bool subreg_offset_representable_p (unsigned int, enum machine_mode, unsigned int, enum machine_mode); extern unsigned int subreg_regno (rtx); +extern unsigned HOST_WIDE_INT nonzero_bits (rtx, enum machine_mode); +extern unsigned int num_sign_bit_copies (rtx, enum machine_mode); + /* 1 if RTX is a subreg containing a reg that is already known to be sign- or zero-extended from the mode of the subreg to the mode of @@ -1598,9 +1601,6 @@ extern rtx gen_rtx_REG_offset (rtx, enum machine_mode, unsigned int, int); extern rtx gen_label_rtx (void); extern int subreg_hard_regno (rtx, int); extern rtx gen_lowpart_common (enum machine_mode, rtx); -extern rtx gen_lowpart_general (enum machine_mode, rtx); -extern rtx (*gen_lowpart) (enum machine_mode mode, rtx x); - /* In cse.c */ extern rtx gen_lowpart_if_possible (enum machine_mode, rtx); @@ -2461,4 +2461,25 @@ extern void simplify_using_condition (rtx, rtx *, struct bitmap_head_def *); /* In ra.c. */ extern void reg_alloc (void); + +struct rtl_hooks +{ + rtx (*gen_lowpart) (enum machine_mode, rtx); + rtx (*reg_nonzero_bits) (rtx, enum machine_mode, rtx, enum machine_mode, + unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT *); + rtx (*reg_num_sign_bit_copies) (rtx, enum machine_mode, rtx, enum machine_mode, + unsigned int, unsigned int *); + + /* Whenever you add entries here, make sure you adjust hosthooks-def.h. */ +}; + +/* Each pass can provide its own. */ +extern struct rtl_hooks rtl_hooks; + +/* ... but then it has to restore these. */ +extern const struct rtl_hooks general_rtl_hooks; + +/* Keep this for the nonce. */ +#define gen_lowpart rtl_hooks.gen_lowpart + #endif /* ! GCC_RTL_H */ diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index a52f614b878..8da8b80ddb3 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -36,6 +36,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "basic-block.h" #include "real.h" #include "regs.h" +#include "function.h" /* Forward declarations */ static int global_reg_mentioned_p_1 (rtx *, void *); @@ -47,6 +48,18 @@ static void parms_set (rtx, rtx, void *); static bool hoist_test_store (rtx, rtx, regset); static void hoist_update_store (rtx, rtx *, rtx, rtx); +static unsigned HOST_WIDE_INT cached_nonzero_bits (rtx, enum machine_mode, + rtx, enum machine_mode, + unsigned HOST_WIDE_INT); +static unsigned HOST_WIDE_INT nonzero_bits1 (rtx, enum machine_mode, rtx, + enum machine_mode, + unsigned HOST_WIDE_INT); +static unsigned int cached_num_sign_bit_copies (rtx, enum machine_mode, rtx, + enum machine_mode, + unsigned int); +static unsigned int num_sign_bit_copies1 (rtx, enum machine_mode, rtx, + enum machine_mode, unsigned int); + /* Bit flags that specify the machine subtype we are compiling for. Bits are tested using macros TARGET_... defined in the tm.h file and set by `-m...' switches. Must be defined in rtlanal.c. */ @@ -3849,3 +3862,946 @@ default_address_cost (rtx x) { return rtx_cost (x, MEM); } + + +unsigned HOST_WIDE_INT +nonzero_bits (rtx x, enum machine_mode mode) +{ + return cached_nonzero_bits (x, mode, NULL_RTX, VOIDmode, 0); +} + +unsigned int +num_sign_bit_copies (rtx x, enum machine_mode mode) +{ + return cached_num_sign_bit_copies (x, mode, NULL_RTX, VOIDmode, 0); +} + +/* The function cached_nonzero_bits is a wrapper around nonzero_bits1. + It avoids exponential behavior in nonzero_bits1 when X has + identical subexpressions on the first or the second level. */ + +static unsigned HOST_WIDE_INT +cached_nonzero_bits (rtx x, enum machine_mode mode, rtx known_x, + enum machine_mode known_mode, + unsigned HOST_WIDE_INT known_ret) +{ + if (x == known_x && mode == known_mode) + return known_ret; + + /* Try to find identical subexpressions. If found call + nonzero_bits1 on X with the subexpressions as KNOWN_X and the + precomputed value for the subexpression as KNOWN_RET. */ + + if (ARITHMETIC_P (x)) + { + rtx x0 = XEXP (x, 0); + rtx x1 = XEXP (x, 1); + + /* Check the first level. */ + if (x0 == x1) + return nonzero_bits1 (x, mode, x0, mode, + cached_nonzero_bits (x0, mode, known_x, + known_mode, known_ret)); + + /* Check the second level. */ + if (ARITHMETIC_P (x0) + && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1))) + return nonzero_bits1 (x, mode, x1, mode, + cached_nonzero_bits (x1, mode, known_x, + known_mode, known_ret)); + + if (ARITHMETIC_P (x1) + && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1))) + return nonzero_bits1 (x, mode, x0, mode, + cached_nonzero_bits (x0, mode, known_x, + known_mode, known_ret)); + } + + return nonzero_bits1 (x, mode, known_x, known_mode, known_ret); +} + +/* We let num_sign_bit_copies recur into nonzero_bits as that is useful. + We don't let nonzero_bits recur into num_sign_bit_copies, because that + is less useful. We can't allow both, because that results in exponential + run time recursion. There is a nullstone testcase that triggered + this. This macro avoids accidental uses of num_sign_bit_copies. */ +#define cached_num_sign_bit_copies sorry_i_am_preventing_exponential_behavior + +/* Given an expression, X, compute which bits in X can be nonzero. + We don't care about bits outside of those defined in MODE. + + For most X this is simply GET_MODE_MASK (GET_MODE (MODE)), but if X is + an arithmetic operation, we can do better. */ + +static unsigned HOST_WIDE_INT +nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x, + enum machine_mode known_mode, + unsigned HOST_WIDE_INT known_ret) +{ + unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode); + unsigned HOST_WIDE_INT inner_nz; + enum rtx_code code; + unsigned int mode_width = GET_MODE_BITSIZE (mode); + + /* For floating-point values, assume all bits are needed. */ + if (FLOAT_MODE_P (GET_MODE (x)) || FLOAT_MODE_P (mode)) + return nonzero; + + /* If X is wider than MODE, use its mode instead. */ + if (GET_MODE_BITSIZE (GET_MODE (x)) > mode_width) + { + mode = GET_MODE (x); + nonzero = GET_MODE_MASK (mode); + mode_width = GET_MODE_BITSIZE (mode); + } + + if (mode_width > HOST_BITS_PER_WIDE_INT) + /* Our only callers in this case look for single bit values. So + just return the mode mask. Those tests will then be false. */ + return nonzero; + +#ifndef WORD_REGISTER_OPERATIONS + /* If MODE is wider than X, but both are a single word for both the host + and target machines, we can compute this from which bits of the + object might be nonzero in its own mode, taking into account the fact + that on many CISC machines, accessing an object in a wider mode + causes the high-order bits to become undefined. So they are + not known to be zero. */ + + if (GET_MODE (x) != VOIDmode && GET_MODE (x) != mode + && GET_MODE_BITSIZE (GET_MODE (x)) <= BITS_PER_WORD + && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT + && GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (GET_MODE (x))) + { + nonzero &= cached_nonzero_bits (x, GET_MODE (x), + known_x, known_mode, known_ret); + nonzero |= GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x)); + return nonzero; + } +#endif + + code = GET_CODE (x); + switch (code) + { + case REG: +#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) + /* If pointers extend unsigned and this is a pointer in Pmode, say that + all the bits above ptr_mode are known to be zero. */ + if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode + && REG_POINTER (x)) + nonzero &= GET_MODE_MASK (ptr_mode); +#endif + + /* Include declared information about alignment of pointers. */ + /* ??? We don't properly preserve REG_POINTER changes across + pointer-to-integer casts, so we can't trust it except for + things that we know must be pointers. See execute/960116-1.c. */ + if ((x == stack_pointer_rtx + || x == frame_pointer_rtx + || x == arg_pointer_rtx) + && REGNO_POINTER_ALIGN (REGNO (x))) + { + unsigned HOST_WIDE_INT alignment + = REGNO_POINTER_ALIGN (REGNO (x)) / BITS_PER_UNIT; + +#ifdef PUSH_ROUNDING + /* If PUSH_ROUNDING is defined, it is possible for the + stack to be momentarily aligned only to that amount, + so we pick the least alignment. */ + if (x == stack_pointer_rtx && PUSH_ARGS) + alignment = MIN ((unsigned HOST_WIDE_INT) PUSH_ROUNDING (1), + alignment); +#endif + + nonzero &= ~(alignment - 1); + } + + { + unsigned HOST_WIDE_INT nonzero_for_hook = nonzero; + rtx new = rtl_hooks.reg_nonzero_bits (x, mode, known_x, + known_mode, known_ret, + &nonzero_for_hook); + + if (new) + nonzero_for_hook &= cached_nonzero_bits (new, mode, known_x, + known_mode, known_ret); + + return nonzero_for_hook; + } + + case CONST_INT: +#ifdef SHORT_IMMEDIATES_SIGN_EXTEND + /* If X is negative in MODE, sign-extend the value. */ + if (INTVAL (x) > 0 && mode_width < BITS_PER_WORD + && 0 != (INTVAL (x) & ((HOST_WIDE_INT) 1 << (mode_width - 1)))) + return (INTVAL (x) | ((HOST_WIDE_INT) (-1) << mode_width)); +#endif + + return INTVAL (x); + + case MEM: +#ifdef LOAD_EXTEND_OP + /* In many, if not most, RISC machines, reading a byte from memory + zeros the rest of the register. Noticing that fact saves a lot + of extra zero-extends. */ + if (LOAD_EXTEND_OP (GET_MODE (x)) == ZERO_EXTEND) + nonzero &= GET_MODE_MASK (GET_MODE (x)); +#endif + break; + + case EQ: case NE: + case UNEQ: case LTGT: + case GT: case GTU: case UNGT: + case LT: case LTU: case UNLT: + case GE: case GEU: case UNGE: + case LE: case LEU: case UNLE: + case UNORDERED: case ORDERED: + + /* If this produces an integer result, we know which bits are set. + Code here used to clear bits outside the mode of X, but that is + now done above. */ + + if (GET_MODE_CLASS (mode) == MODE_INT + && mode_width <= HOST_BITS_PER_WIDE_INT) + nonzero = STORE_FLAG_VALUE; + break; + + case NEG: +#if 0 + /* Disabled to avoid exponential mutual recursion between nonzero_bits + and num_sign_bit_copies. */ + if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x)) + == GET_MODE_BITSIZE (GET_MODE (x))) + nonzero = 1; +#endif + + if (GET_MODE_SIZE (GET_MODE (x)) < mode_width) + nonzero |= (GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x))); + break; + + case ABS: +#if 0 + /* Disabled to avoid exponential mutual recursion between nonzero_bits + and num_sign_bit_copies. */ + if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x)) + == GET_MODE_BITSIZE (GET_MODE (x))) + nonzero = 1; +#endif + break; + + case TRUNCATE: + nonzero &= (cached_nonzero_bits (XEXP (x, 0), mode, + known_x, known_mode, known_ret) + & GET_MODE_MASK (mode)); + break; + + case ZERO_EXTEND: + nonzero &= cached_nonzero_bits (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + if (GET_MODE (XEXP (x, 0)) != VOIDmode) + nonzero &= GET_MODE_MASK (GET_MODE (XEXP (x, 0))); + break; + + case SIGN_EXTEND: + /* If the sign bit is known clear, this is the same as ZERO_EXTEND. + Otherwise, show all the bits in the outer mode but not the inner + may be nonzero. */ + inner_nz = cached_nonzero_bits (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + if (GET_MODE (XEXP (x, 0)) != VOIDmode) + { + inner_nz &= GET_MODE_MASK (GET_MODE (XEXP (x, 0))); + if (inner_nz + & (((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1)))) + inner_nz |= (GET_MODE_MASK (mode) + & ~GET_MODE_MASK (GET_MODE (XEXP (x, 0)))); + } + + nonzero &= inner_nz; + break; + + case AND: + nonzero &= cached_nonzero_bits (XEXP (x, 0), mode, + known_x, known_mode, known_ret) + & cached_nonzero_bits (XEXP (x, 1), mode, + known_x, known_mode, known_ret); + break; + + case XOR: case IOR: + case UMIN: case UMAX: case SMIN: case SMAX: + { + unsigned HOST_WIDE_INT nonzero0 = + cached_nonzero_bits (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + + /* Don't call nonzero_bits for the second time if it cannot change + anything. */ + if ((nonzero & nonzero0) != nonzero) + nonzero &= nonzero0 + | cached_nonzero_bits (XEXP (x, 1), mode, + known_x, known_mode, known_ret); + } + break; + + case PLUS: case MINUS: + case MULT: + case DIV: case UDIV: + case MOD: case UMOD: + /* We can apply the rules of arithmetic to compute the number of + high- and low-order zero bits of these operations. We start by + computing the width (position of the highest-order nonzero bit) + and the number of low-order zero bits for each value. */ + { + unsigned HOST_WIDE_INT nz0 = + cached_nonzero_bits (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + unsigned HOST_WIDE_INT nz1 = + cached_nonzero_bits (XEXP (x, 1), mode, + known_x, known_mode, known_ret); + int sign_index = GET_MODE_BITSIZE (GET_MODE (x)) - 1; + int width0 = floor_log2 (nz0) + 1; + int width1 = floor_log2 (nz1) + 1; + int low0 = floor_log2 (nz0 & -nz0); + int low1 = floor_log2 (nz1 & -nz1); + HOST_WIDE_INT op0_maybe_minusp + = (nz0 & ((HOST_WIDE_INT) 1 << sign_index)); + HOST_WIDE_INT op1_maybe_minusp + = (nz1 & ((HOST_WIDE_INT) 1 << sign_index)); + unsigned int result_width = mode_width; + int result_low = 0; + + switch (code) + { + case PLUS: + result_width = MAX (width0, width1) + 1; + result_low = MIN (low0, low1); + break; + case MINUS: + result_low = MIN (low0, low1); + break; + case MULT: + result_width = width0 + width1; + result_low = low0 + low1; + break; + case DIV: + if (width1 == 0) + break; + if (! op0_maybe_minusp && ! op1_maybe_minusp) + result_width = width0; + break; + case UDIV: + if (width1 == 0) + break; + result_width = width0; + break; + case MOD: + if (width1 == 0) + break; + if (! op0_maybe_minusp && ! op1_maybe_minusp) + result_width = MIN (width0, width1); + result_low = MIN (low0, low1); + break; + case UMOD: + if (width1 == 0) + break; + result_width = MIN (width0, width1); + result_low = MIN (low0, low1); + break; + default: + abort (); + } + + if (result_width < mode_width) + nonzero &= ((HOST_WIDE_INT) 1 << result_width) - 1; + + if (result_low > 0) + nonzero &= ~(((HOST_WIDE_INT) 1 << result_low) - 1); + +#ifdef POINTERS_EXTEND_UNSIGNED + /* If pointers extend unsigned and this is an addition or subtraction + to a pointer in Pmode, all the bits above ptr_mode are known to be + zero. */ + if (POINTERS_EXTEND_UNSIGNED > 0 && GET_MODE (x) == Pmode + && (code == PLUS || code == MINUS) + && GET_CODE (XEXP (x, 0)) == REG && REG_POINTER (XEXP (x, 0))) + nonzero &= GET_MODE_MASK (ptr_mode); +#endif + } + break; + + case ZERO_EXTRACT: + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT) + nonzero &= ((HOST_WIDE_INT) 1 << INTVAL (XEXP (x, 1))) - 1; + break; + + case SUBREG: + /* If this is a SUBREG formed for a promoted variable that has + been zero-extended, we know that at least the high-order bits + are zero, though others might be too. */ + + if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x) > 0) + nonzero = GET_MODE_MASK (GET_MODE (x)) + & cached_nonzero_bits (SUBREG_REG (x), GET_MODE (x), + known_x, known_mode, known_ret); + + /* If the inner mode is a single word for both the host and target + machines, we can compute this from which bits of the inner + object might be nonzero. */ + if (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) <= BITS_PER_WORD + && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) + <= HOST_BITS_PER_WIDE_INT)) + { + nonzero &= cached_nonzero_bits (SUBREG_REG (x), mode, + known_x, known_mode, known_ret); + +#if defined (WORD_REGISTER_OPERATIONS) && defined (LOAD_EXTEND_OP) + /* If this is a typical RISC machine, we only have to worry + about the way loads are extended. */ + if ((LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND + ? (((nonzero + & (((unsigned HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1)))) + != 0)) + : LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) != ZERO_EXTEND) + || GET_CODE (SUBREG_REG (x)) != MEM) +#endif + { + /* On many CISC machines, accessing an object in a wider mode + causes the high-order bits to become undefined. So they are + not known to be zero. */ + if (GET_MODE_SIZE (GET_MODE (x)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) + nonzero |= (GET_MODE_MASK (GET_MODE (x)) + & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))); + } + } + break; + + case ASHIFTRT: + case LSHIFTRT: + case ASHIFT: + case ROTATE: + /* The nonzero bits are in two classes: any bits within MODE + that aren't in GET_MODE (x) are always significant. The rest of the + nonzero bits are those that are significant in the operand of + the shift when shifted the appropriate number of bits. This + shows that high-order bits are cleared by the right shift and + low-order bits by left shifts. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) >= 0 + && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT) + { + enum machine_mode inner_mode = GET_MODE (x); + unsigned int width = GET_MODE_BITSIZE (inner_mode); + int count = INTVAL (XEXP (x, 1)); + unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (inner_mode); + unsigned HOST_WIDE_INT op_nonzero = + cached_nonzero_bits (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + unsigned HOST_WIDE_INT inner = op_nonzero & mode_mask; + unsigned HOST_WIDE_INT outer = 0; + + if (mode_width > width) + outer = (op_nonzero & nonzero & ~mode_mask); + + if (code == LSHIFTRT) + inner >>= count; + else if (code == ASHIFTRT) + { + inner >>= count; + + /* If the sign bit may have been nonzero before the shift, we + need to mark all the places it could have been copied to + by the shift as possibly nonzero. */ + if (inner & ((HOST_WIDE_INT) 1 << (width - 1 - count))) + inner |= (((HOST_WIDE_INT) 1 << count) - 1) << (width - count); + } + else if (code == ASHIFT) + inner <<= count; + else + inner = ((inner << (count % width) + | (inner >> (width - (count % width)))) & mode_mask); + + nonzero &= (outer | inner); + } + break; + + case FFS: + case POPCOUNT: + /* This is at most the number of bits in the mode. */ + nonzero = ((HOST_WIDE_INT) 2 << (floor_log2 (mode_width))) - 1; + break; + + case CLZ: + /* If CLZ has a known value at zero, then the nonzero bits are + that value, plus the number of bits in the mode minus one. */ + if (CLZ_DEFINED_VALUE_AT_ZERO (mode, nonzero)) + nonzero |= ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1; + else + nonzero = -1; + break; + + case CTZ: + /* If CTZ has a known value at zero, then the nonzero bits are + that value, plus the number of bits in the mode minus one. */ + if (CTZ_DEFINED_VALUE_AT_ZERO (mode, nonzero)) + nonzero |= ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1; + else + nonzero = -1; + break; + + case PARITY: + nonzero = 1; + break; + + case IF_THEN_ELSE: + { + unsigned HOST_WIDE_INT nonzero_true = + cached_nonzero_bits (XEXP (x, 1), mode, + known_x, known_mode, known_ret); + + /* Don't call nonzero_bits for the second time if it cannot change + anything. */ + if ((nonzero & nonzero_true) != nonzero) + nonzero &= nonzero_true + | cached_nonzero_bits (XEXP (x, 2), mode, + known_x, known_mode, known_ret); + } + break; + + default: + break; + } + + return nonzero; +} + +/* See the macro definition above. */ +#undef cached_num_sign_bit_copies + + +/* The function cached_num_sign_bit_copies is a wrapper around + num_sign_bit_copies1. It avoids exponential behavior in + num_sign_bit_copies1 when X has identical subexpressions on the + first or the second level. */ + +static unsigned int +cached_num_sign_bit_copies (rtx x, enum machine_mode mode, rtx known_x, + enum machine_mode known_mode, + unsigned int known_ret) +{ + if (x == known_x && mode == known_mode) + return known_ret; + + /* Try to find identical subexpressions. If found call + num_sign_bit_copies1 on X with the subexpressions as KNOWN_X and + the precomputed value for the subexpression as KNOWN_RET. */ + + if (ARITHMETIC_P (x)) + { + rtx x0 = XEXP (x, 0); + rtx x1 = XEXP (x, 1); + + /* Check the first level. */ + if (x0 == x1) + return + num_sign_bit_copies1 (x, mode, x0, mode, + cached_num_sign_bit_copies (x0, mode, known_x, + known_mode, + known_ret)); + + /* Check the second level. */ + if (ARITHMETIC_P (x0) + && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1))) + return + num_sign_bit_copies1 (x, mode, x1, mode, + cached_num_sign_bit_copies (x1, mode, known_x, + known_mode, + known_ret)); + + if (ARITHMETIC_P (x1) + && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1))) + return + num_sign_bit_copies1 (x, mode, x0, mode, + cached_num_sign_bit_copies (x0, mode, known_x, + known_mode, + known_ret)); + } + + return num_sign_bit_copies1 (x, mode, known_x, known_mode, known_ret); +} + +/* Return the number of bits at the high-order end of X that are known to + be equal to the sign bit. X will be used in mode MODE; if MODE is + VOIDmode, X will be used in its own mode. The returned value will always + be between 1 and the number of bits in MODE. */ + +static unsigned int +num_sign_bit_copies1 (rtx x, enum machine_mode mode, rtx known_x, + enum machine_mode known_mode, + unsigned int known_ret) +{ + enum rtx_code code = GET_CODE (x); + unsigned int bitwidth = GET_MODE_BITSIZE (mode); + int num0, num1, result; + unsigned HOST_WIDE_INT nonzero; + + /* If we weren't given a mode, use the mode of X. If the mode is still + VOIDmode, we don't know anything. Likewise if one of the modes is + floating-point. */ + + if (mode == VOIDmode) + mode = GET_MODE (x); + + if (mode == VOIDmode || FLOAT_MODE_P (mode) || FLOAT_MODE_P (GET_MODE (x))) + return 1; + + /* For a smaller object, just ignore the high bits. */ + if (bitwidth < GET_MODE_BITSIZE (GET_MODE (x))) + { + num0 = cached_num_sign_bit_copies (x, GET_MODE (x), + known_x, known_mode, known_ret); + return MAX (1, + num0 - (int) (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth)); + } + + if (GET_MODE (x) != VOIDmode && bitwidth > GET_MODE_BITSIZE (GET_MODE (x))) + { +#ifndef WORD_REGISTER_OPERATIONS + /* If this machine does not do all register operations on the entire + register and MODE is wider than the mode of X, we can say nothing + at all about the high-order bits. */ + return 1; +#else + /* Likewise on machines that do, if the mode of the object is smaller + than a word and loads of that size don't sign extend, we can say + nothing about the high order bits. */ + if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD +#ifdef LOAD_EXTEND_OP + && LOAD_EXTEND_OP (GET_MODE (x)) != SIGN_EXTEND +#endif + ) + return 1; +#endif + } + + switch (code) + { + case REG: + +#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) + /* If pointers extend signed and this is a pointer in Pmode, say that + all the bits above ptr_mode are known to be sign bit copies. */ + if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && mode == Pmode + && REG_POINTER (x)) + return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1; +#endif + + { + unsigned int copies_for_hook = 1, copies = 1; + rtx new = rtl_hooks.reg_num_sign_bit_copies (x, mode, known_x, + known_mode, known_ret, + &copies_for_hook); + + if (new) + copies = cached_num_sign_bit_copies (new, mode, known_x, + known_mode, known_ret); + + if (copies > 1 || copies_for_hook > 1) + return MAX (copies, copies_for_hook); + + /* Else, use nonzero_bits to guess num_sign_bit_copies (see below). */ + } + break; + + case MEM: +#ifdef LOAD_EXTEND_OP + /* Some RISC machines sign-extend all loads of smaller than a word. */ + if (LOAD_EXTEND_OP (GET_MODE (x)) == SIGN_EXTEND) + return MAX (1, ((int) bitwidth + - (int) GET_MODE_BITSIZE (GET_MODE (x)) + 1)); +#endif + break; + + case CONST_INT: + /* If the constant is negative, take its 1's complement and remask. + Then see how many zero bits we have. */ + nonzero = INTVAL (x) & GET_MODE_MASK (mode); + if (bitwidth <= HOST_BITS_PER_WIDE_INT + && (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0) + nonzero = (~nonzero) & GET_MODE_MASK (mode); + + return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1); + + case SUBREG: + /* If this is a SUBREG for a promoted object that is sign-extended + and we are looking at it in a wider mode, we know that at least the + high-order bits are known to be sign bit copies. */ + + if (SUBREG_PROMOTED_VAR_P (x) && ! SUBREG_PROMOTED_UNSIGNED_P (x)) + { + num0 = cached_num_sign_bit_copies (SUBREG_REG (x), mode, + known_x, known_mode, known_ret); + return MAX ((int) bitwidth + - (int) GET_MODE_BITSIZE (GET_MODE (x)) + 1, + num0); + } + + /* For a smaller object, just ignore the high bits. */ + if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))) + { + num0 = cached_num_sign_bit_copies (SUBREG_REG (x), VOIDmode, + known_x, known_mode, known_ret); + return MAX (1, (num0 + - (int) (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) + - bitwidth))); + } + +#ifdef WORD_REGISTER_OPERATIONS +#ifdef LOAD_EXTEND_OP + /* For paradoxical SUBREGs on machines where all register operations + affect the entire register, just look inside. Note that we are + passing MODE to the recursive call, so the number of sign bit copies + will remain relative to that mode, not the inner mode. */ + + /* This works only if loads sign extend. Otherwise, if we get a + reload for the inner part, it may be loaded from the stack, and + then we lose all sign bit copies that existed before the store + to the stack. */ + + if ((GET_MODE_SIZE (GET_MODE (x)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) + && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND + && GET_CODE (SUBREG_REG (x)) == MEM) + return cached_num_sign_bit_copies (SUBREG_REG (x), mode, + known_x, known_mode, known_ret); +#endif +#endif + break; + + case SIGN_EXTRACT: + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + return MAX (1, (int) bitwidth - INTVAL (XEXP (x, 1))); + break; + + case SIGN_EXTEND: + return (bitwidth - GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) + + cached_num_sign_bit_copies (XEXP (x, 0), VOIDmode, + known_x, known_mode, known_ret)); + + case TRUNCATE: + /* For a smaller object, just ignore the high bits. */ + num0 = cached_num_sign_bit_copies (XEXP (x, 0), VOIDmode, + known_x, known_mode, known_ret); + return MAX (1, (num0 - (int) (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) + - bitwidth))); + + case NOT: + return cached_num_sign_bit_copies (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + + case ROTATE: case ROTATERT: + /* If we are rotating left by a number of bits less than the number + of sign bit copies, we can just subtract that amount from the + number. */ + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) >= 0 + && INTVAL (XEXP (x, 1)) < (int) bitwidth) + { + num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + return MAX (1, num0 - (code == ROTATE ? INTVAL (XEXP (x, 1)) + : (int) bitwidth - INTVAL (XEXP (x, 1)))); + } + break; + + case NEG: + /* In general, this subtracts one sign bit copy. But if the value + is known to be positive, the number of sign bit copies is the + same as that of the input. Finally, if the input has just one bit + that might be nonzero, all the bits are copies of the sign bit. */ + num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + if (bitwidth > HOST_BITS_PER_WIDE_INT) + return num0 > 1 ? num0 - 1 : 1; + + nonzero = nonzero_bits (XEXP (x, 0), mode); + if (nonzero == 1) + return bitwidth; + + if (num0 > 1 + && (((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero)) + num0--; + + return num0; + + case IOR: case AND: case XOR: + case SMIN: case SMAX: case UMIN: case UMAX: + /* Logical operations will preserve the number of sign-bit copies. + MIN and MAX operations always return one of the operands. */ + num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + num1 = cached_num_sign_bit_copies (XEXP (x, 1), mode, + known_x, known_mode, known_ret); + return MIN (num0, num1); + + case PLUS: case MINUS: + /* For addition and subtraction, we can have a 1-bit carry. However, + if we are subtracting 1 from a positive number, there will not + be such a carry. Furthermore, if the positive number is known to + be 0 or 1, we know the result is either -1 or 0. */ + + if (code == PLUS && XEXP (x, 1) == constm1_rtx + && bitwidth <= HOST_BITS_PER_WIDE_INT) + { + nonzero = nonzero_bits (XEXP (x, 0), mode); + if ((((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero) == 0) + return (nonzero == 1 || nonzero == 0 ? bitwidth + : bitwidth - floor_log2 (nonzero) - 1); + } + + num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + num1 = cached_num_sign_bit_copies (XEXP (x, 1), mode, + known_x, known_mode, known_ret); + result = MAX (1, MIN (num0, num1) - 1); + +#ifdef POINTERS_EXTEND_UNSIGNED + /* If pointers extend signed and this is an addition or subtraction + to a pointer in Pmode, all the bits above ptr_mode are known to be + sign bit copies. */ + if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode + && (code == PLUS || code == MINUS) + && GET_CODE (XEXP (x, 0)) == REG && REG_POINTER (XEXP (x, 0))) + result = MAX ((int) (GET_MODE_BITSIZE (Pmode) + - GET_MODE_BITSIZE (ptr_mode) + 1), + result); +#endif + return result; + + case MULT: + /* The number of bits of the product is the sum of the number of + bits of both terms. However, unless one of the terms if known + to be positive, we must allow for an additional bit since negating + a negative number can remove one sign bit copy. */ + + num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + num1 = cached_num_sign_bit_copies (XEXP (x, 1), mode, + known_x, known_mode, known_ret); + + result = bitwidth - (bitwidth - num0) - (bitwidth - num1); + if (result > 0 + && (bitwidth > HOST_BITS_PER_WIDE_INT + || (((nonzero_bits (XEXP (x, 0), mode) + & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0) + && ((nonzero_bits (XEXP (x, 1), mode) + & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)))) + result--; + + return MAX (1, result); + + case UDIV: + /* The result must be <= the first operand. If the first operand + has the high bit set, we know nothing about the number of sign + bit copies. */ + if (bitwidth > HOST_BITS_PER_WIDE_INT) + return 1; + else if ((nonzero_bits (XEXP (x, 0), mode) + & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0) + return 1; + else + return cached_num_sign_bit_copies (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + + case UMOD: + /* The result must be <= the second operand. */ + return cached_num_sign_bit_copies (XEXP (x, 1), mode, + known_x, known_mode, known_ret); + + case DIV: + /* Similar to unsigned division, except that we have to worry about + the case where the divisor is negative, in which case we have + to add 1. */ + result = cached_num_sign_bit_copies (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + if (result > 1 + && (bitwidth > HOST_BITS_PER_WIDE_INT + || (nonzero_bits (XEXP (x, 1), mode) + & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)) + result--; + + return result; + + case MOD: + result = cached_num_sign_bit_copies (XEXP (x, 1), mode, + known_x, known_mode, known_ret); + if (result > 1 + && (bitwidth > HOST_BITS_PER_WIDE_INT + || (nonzero_bits (XEXP (x, 1), mode) + & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)) + result--; + + return result; + + case ASHIFTRT: + /* Shifts by a constant add to the number of bits equal to the + sign bit. */ + num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + if (GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) > 0) + num0 = MIN ((int) bitwidth, num0 + INTVAL (XEXP (x, 1))); + + return num0; + + case ASHIFT: + /* Left shifts destroy copies. */ + if (GET_CODE (XEXP (x, 1)) != CONST_INT + || INTVAL (XEXP (x, 1)) < 0 + || INTVAL (XEXP (x, 1)) >= (int) bitwidth) + return 1; + + num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode, + known_x, known_mode, known_ret); + return MAX (1, num0 - INTVAL (XEXP (x, 1))); + + case IF_THEN_ELSE: + num0 = cached_num_sign_bit_copies (XEXP (x, 1), mode, + known_x, known_mode, known_ret); + num1 = cached_num_sign_bit_copies (XEXP (x, 2), mode, + known_x, known_mode, known_ret); + return MIN (num0, num1); + + case EQ: case NE: case GE: case GT: case LE: case LT: + case UNEQ: case LTGT: case UNGE: case UNGT: case UNLE: case UNLT: + case GEU: case GTU: case LEU: case LTU: + case UNORDERED: case ORDERED: + /* If the constant is negative, take its 1's complement and remask. + Then see how many zero bits we have. */ + nonzero = STORE_FLAG_VALUE; + if (bitwidth <= HOST_BITS_PER_WIDE_INT + && (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0) + nonzero = (~nonzero) & GET_MODE_MASK (mode); + + return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1); + + default: + break; + } + + /* If we haven't been able to figure it out by one of the above rules, + see if some of the high-order bits are known to be zero. If so, + count those bits and return one less than that amount. If we can't + safely compute the mask for this mode, always return BITWIDTH. */ + + bitwidth = GET_MODE_BITSIZE (mode); + if (bitwidth > HOST_BITS_PER_WIDE_INT) + return 1; + + nonzero = nonzero_bits (x, mode); + return nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1)) + ? 1 : bitwidth - floor_log2 (nonzero) - 1; +} diff --git a/gcc/rtlhooks-def.h b/gcc/rtlhooks-def.h new file mode 100644 index 00000000000..aaae80cab8c --- /dev/null +++ b/gcc/rtlhooks-def.h @@ -0,0 +1,46 @@ +/* Default macros to initialize an rtl_hooks data structure. + Copyright 2004 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef GCC_RTL_HOOKS_DEF_H +#define GCC_RTL_HOOKS_DEF_H + +#include "rtl.h" + +#define RTL_HOOKS_GEN_LOWPART gen_lowpart_general +#define RTL_HOOKS_REG_NONZERO_REG_BITS reg_nonzero_bits_general +#define RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES reg_num_sign_bit_copies_general + +/* The structure is defined in rtl.h. */ +#define RTL_HOOKS_INITIALIZER { \ + RTL_HOOKS_GEN_LOWPART, \ + RTL_HOOKS_REG_NONZERO_REG_BITS, \ + RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES, \ +} + +extern rtx gen_lowpart_general (enum machine_mode, rtx); +extern rtx reg_nonzero_bits_general (rtx, enum machine_mode, rtx, + enum machine_mode, + unsigned HOST_WIDE_INT, + unsigned HOST_WIDE_INT *); +extern rtx reg_num_sign_bit_copies_general (rtx, enum machine_mode, rtx, + enum machine_mode, + unsigned int, unsigned int *); + +#endif /* GCC_RTL_HOOKS_DEF_H */ diff --git a/gcc/rtlhooks.c b/gcc/rtlhooks.c new file mode 100644 index 00000000000..b27cecea2ca --- /dev/null +++ b/gcc/rtlhooks.c @@ -0,0 +1,105 @@ +/* Generic hooks for the RTL middle-end. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "rtlhooks-def.h" +#include "expr.h" + + +/* For speed, we will copy the RTX hooks struct member-by-member + instead of doing indirect calls. For these reason, we initialize + *two* struct rtl_hooks globals: rtl_hooks is the one that is used + to actually call the hooks, while general_rtl_hooks is used + to restore the hooks by passes that modify them. */ + +const struct rtl_hooks general_rtl_hooks = RTL_HOOKS_INITIALIZER; +struct rtl_hooks rtl_hooks = RTL_HOOKS_INITIALIZER; + +rtx +gen_lowpart_general (enum machine_mode mode, rtx x) +{ + rtx result = gen_lowpart_common (mode, x); + + if (result) + return result; + else if (GET_CODE (x) == REG) + { + /* Must be a hard reg that's not valid in MODE. */ + result = gen_lowpart_common (mode, copy_to_reg (x)); + if (result == 0) + abort (); + return result; + } + else if (GET_CODE (x) == MEM) + { + /* The only additional case we can do is MEM. */ + int offset = 0; + + /* The following exposes the use of "x" to CSE. */ + if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD + && SCALAR_INT_MODE_P (GET_MODE (x)) + && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), + GET_MODE_BITSIZE (GET_MODE (x))) + && ! no_new_pseudos) + return gen_lowpart_general (mode, force_reg (GET_MODE (x), x)); + + if (WORDS_BIG_ENDIAN) + offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) + - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)); + + if (BYTES_BIG_ENDIAN) + /* Adjust the address so that the address-after-the-data + is unchanged. */ + offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)) + - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); + + return adjust_address (x, mode, offset); + } + else if (GET_CODE (x) == ADDRESSOF) + return gen_lowpart_general (mode, force_reg (GET_MODE (x), x)); + else + abort (); +} + +rtx +reg_num_sign_bit_copies_general (rtx x ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + rtx known_x ATTRIBUTE_UNUSED, + enum machine_mode known_mode ATTRIBUTE_UNUSED, + unsigned int known_ret ATTRIBUTE_UNUSED, + unsigned int *result ATTRIBUTE_UNUSED) +{ + return NULL; +} + +rtx +reg_nonzero_bits_general (rtx x ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + rtx known_x ATTRIBUTE_UNUSED, + enum machine_mode known_mode ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT known_ret ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT *nonzero ATTRIBUTE_UNUSED) +{ + return NULL; +}