From: hubicka Date: Mon, 4 Jun 2001 14:52:14 +0000 (+0000) Subject: * simplify_rtx.c (simplify_subreg): Keep subregs on return values, X-Git-Tag: upstream/4.9.2~94012 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=81802af67bf22f3decf31100628f236650275ddb;p=platform%2Fupstream%2Flinaro-gcc.git * simplify_rtx.c (simplify_subreg): Keep subregs on return values, check CLASS_CANNOT_CHANGE_MODE before avoiding subreg on hard reg, in case register wasn't OK previously, accept it now; allow subregs of frame pointer if reload completed and frame pointer is not needed. * combine.c (sombine_simplify_rtx): Fix comment; use subreg_lowpart_offset instead of subreg_lowpart_p (gen_lowpart_for_combine): Use subreg_lowpart_offset. * rtl.h (subreg_lowpart_parts_p): Kill. (subreg_lowpart_offset, subreg_highpart_offset): Declare. * simplify-rtx.c (simplify_subreg): Use subreg_lowpart_offset. * emit-rtl.c (gen_lowpart_SUBREG): Use subreg_lowpart_offset; (gen_lowpart_common): Likewise. (subreg_lowpart_p): Likewise. (subreg_lowpart_parts_p): Kill. (subreg_lowpart_offset, subreg_highpart_offset): New function. * emit-rtl.c (gen_lowpart_common): Use simplify_gen_subreg to simplify SUBREG and REG. (gen_highpart): Use simplify_gen_subreg for all simplifications. * emit-rtl.c (gen_realpart, gen_imagpart): Do not handle CONCAT specially. * rtlanal.c (replace_regs): Use simplify_gen_subreg git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@42850 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b688945..d387b24 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,32 @@ +Mon Jun 4 16:50:33 CEST 2001 Jan Hubicka + + * simplify_rtx.c (simplify_subreg): Keep subregs on return values, + check CLASS_CANNOT_CHANGE_MODE before avoiding subreg on hard reg, + in case register wasn't OK previously, accept it now; allow + subregs of frame pointer if reload completed and frame pointer + is not needed. + + * combine.c (sombine_simplify_rtx): Fix comment; + use subreg_lowpart_offset instead of subreg_lowpart_p + (gen_lowpart_for_combine): Use subreg_lowpart_offset. + * rtl.h (subreg_lowpart_parts_p): Kill. + (subreg_lowpart_offset, subreg_highpart_offset): Declare. + * simplify-rtx.c (simplify_subreg): Use subreg_lowpart_offset. + * emit-rtl.c (gen_lowpart_SUBREG): Use subreg_lowpart_offset; + (gen_lowpart_common): Likewise. + (subreg_lowpart_p): Likewise. + (subreg_lowpart_parts_p): Kill. + (subreg_lowpart_offset, subreg_highpart_offset): New function. + + * emit-rtl.c (gen_lowpart_common): Use simplify_gen_subreg + to simplify SUBREG and REG. + (gen_highpart): Use simplify_gen_subreg for all simplifications. + + * emit-rtl.c (gen_realpart, gen_imagpart): Do not handle + CONCAT specially. + + * rtlanal.c (replace_regs): Use simplify_gen_subreg + Mon Jun 4 09:21:19 2001 Richard Kenner * tree.def (ARRAY_RANGE_REF): New code. diff --git a/gcc/combine.c b/gcc/combine.c index bfa97b0..e34ab2f 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -3715,7 +3715,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest) /* If CODE is an associative operation not otherwise handled, see if we can associate some operands. This can win if they are constants or - if they are logically related (i.e. (a & b) & a. */ + if they are logically related (i.e. (a & b) & a). */ if ((code == PLUS || code == MINUS || code == MULT || code == AND || code == IOR || code == XOR || code == DIV || code == UDIV @@ -3774,7 +3774,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest) /* simplify_subreg can't use gen_lowpart_for_combine. */ if (CONSTANT_P (SUBREG_REG (x)) - && subreg_lowpart_parts_p (mode, op0_mode, SUBREG_BYTE (x))) + && subreg_lowpart_offset (mode, op0_mode) == SUBREG_BYTE (x)) return gen_lowpart_for_combine (mode, SUBREG_REG (x)); { @@ -9765,18 +9765,13 @@ gen_lowpart_for_combine (mode, x) else { int offset = 0; + rtx res; - if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN) - && GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (mode)) - { - int difference = (GET_MODE_SIZE (GET_MODE (x)) - - GET_MODE_SIZE (mode)); - if (WORDS_BIG_ENDIAN) - offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; - if (BYTES_BIG_ENDIAN) - offset += difference % UNITS_PER_WORD; - } - return gen_rtx_SUBREG (mode, x, offset); + offset = subreg_lowpart_offset (mode, GET_MODE (x)); + res = simplify_gen_subreg (mode, x, GET_MODE (x), offset); + if (res) + return res; + return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); } } diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 7a98f20..6c72a99 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -381,22 +381,12 @@ gen_lowpart_SUBREG (mode, reg) rtx reg; { enum machine_mode inmode; - int offset; inmode = GET_MODE (reg); if (inmode == VOIDmode) inmode = mode; - offset = 0; - if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (inmode) - && (WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)) - { - offset = GET_MODE_SIZE (inmode) - GET_MODE_SIZE (mode); - if (! BYTES_BIG_ENDIAN) - offset = (offset / UNITS_PER_WORD) * UNITS_PER_WORD; - else if (! WORDS_BIG_ENDIAN) - offset %= UNITS_PER_WORD; - } - return gen_rtx_SUBREG (mode, reg, offset); + return gen_rtx_SUBREG (mode, reg, + subreg_lowpart_offset (mode, inmode)); } /* rtx gen_rtx (code, mode, [element1, ..., elementn]) @@ -761,16 +751,7 @@ gen_lowpart_common (mode, x) > ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))) return 0; - if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN) - && xsize > msize) - { - int difference = xsize - msize; - - if (WORDS_BIG_ENDIAN) - offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; - if (BYTES_BIG_ENDIAN) - offset += difference % UNITS_PER_WORD; - } + offset = subreg_lowpart_offset (mode, GET_MODE (x)); if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND) && (GET_MODE_CLASS (mode) == MODE_INT @@ -791,61 +772,8 @@ gen_lowpart_common (mode, x) else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))) return gen_rtx_fmt_e (GET_CODE (x), mode, XEXP (x, 0)); } - else if (GET_CODE (x) == SUBREG - && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD - || GET_MODE_SIZE (mode) == GET_MODE_UNIT_SIZE (GET_MODE (x)))) - { - int final_offset; - - if (GET_MODE (SUBREG_REG (x)) == mode && subreg_lowpart_p (x)) - return SUBREG_REG (x); - - /* When working with SUBREGs the rule is that the byte - offset must be a multiple of the SUBREG's mode. */ - final_offset = SUBREG_BYTE (x) + offset; - final_offset = (final_offset / GET_MODE_SIZE (mode)); - final_offset = (final_offset * GET_MODE_SIZE (mode)); - return gen_rtx_SUBREG (mode, SUBREG_REG (x), final_offset); - } - else if (GET_CODE (x) == REG) - { - /* Hard registers are done specially in certain cases. */ - if (REGNO (x) < FIRST_PSEUDO_REGISTER) - { - int final_regno = REGNO (x) + - subreg_regno_offset (REGNO (x), GET_MODE (x), - offset, mode); - - /* If the final regno is not valid for MODE, punt. */ - /* ??? We do allow it if the current REG is not valid for - ??? it's mode. It is a kludge to work around how float/complex - ??? arguments are passed on 32-bit Sparc and should be fixed. */ - if (! HARD_REGNO_MODE_OK (final_regno, mode) - && HARD_REGNO_MODE_OK (REGNO (x), GET_MODE (x))) - return 0; - - /* integrate.c can't handle parts of a return value register. */ - if ((! REG_FUNCTION_VALUE_P (x) - || ! rtx_equal_function_value_matters) -#ifdef CLASS_CANNOT_CHANGE_MODE - && ! (CLASS_CANNOT_CHANGE_MODE_P (mode, GET_MODE (x)) - && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_INT - && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_FLOAT - && (TEST_HARD_REG_BIT - (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], - REGNO (x)))) -#endif - /* We want to keep the stack, frame, and arg pointers - special. */ - && x != frame_pointer_rtx -#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM - && x != arg_pointer_rtx -#endif - && x != stack_pointer_rtx) - return gen_rtx_REG (mode, final_regno); - } - return gen_rtx_SUBREG (mode, x, offset); - } + else if (GET_CODE (x) == SUBREG || GET_CODE (x) == REG || GET_CODE (x) == CONCAT) + return simplify_gen_subreg (mode, x, GET_MODE (x), offset); /* If X is a CONST_INT or a CONST_DOUBLE, extract the appropriate bits from the low-order part of the constant. */ else if ((GET_MODE_CLASS (mode) == MODE_INT @@ -1088,12 +1016,10 @@ gen_realpart (mode, x) enum machine_mode mode; register rtx x; { - if (GET_CODE (x) == CONCAT && GET_MODE (XEXP (x, 0)) == mode) - return XEXP (x, 0); - else if (WORDS_BIG_ENDIAN - && GET_MODE_BITSIZE (mode) < BITS_PER_WORD - && REG_P (x) - && REGNO (x) < FIRST_PSEUDO_REGISTER) + if (WORDS_BIG_ENDIAN + && GET_MODE_BITSIZE (mode) < BITS_PER_WORD + && REG_P (x) + && REGNO (x) < FIRST_PSEUDO_REGISTER) internal_error ("Can't access real part of complex value in hard register"); else if (WORDS_BIG_ENDIAN) @@ -1110,9 +1036,7 @@ gen_imagpart (mode, x) enum machine_mode mode; register rtx x; { - if (GET_CODE (x) == CONCAT && GET_MODE (XEXP (x, 0)) == mode) - return XEXP (x, 1); - else if (WORDS_BIG_ENDIAN) + if (WORDS_BIG_ENDIAN) return gen_lowpart (mode, x); else if (! WORDS_BIG_ENDIAN && GET_MODE_BITSIZE (mode) < BITS_PER_WORD @@ -1195,109 +1119,62 @@ gen_highpart (mode, x) register rtx x; { unsigned int msize = GET_MODE_SIZE (mode); - unsigned int xsize = GET_MODE_SIZE (GET_MODE (x)); + rtx result; /* This case loses if X is a subreg. To catch bugs early, complain if an invalid MODE is used even in other cases. */ if (msize > UNITS_PER_WORD && msize != GET_MODE_UNIT_SIZE (GET_MODE (x))) abort (); - if (GET_CODE (x) == CONST_DOUBLE -#if !(TARGET_FLOAT_FORMAT != HOST_FLOAT_FORMAT || defined (REAL_IS_NOT_DOUBLE)) - && GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT -#endif - ) - return GEN_INT (CONST_DOUBLE_HIGH (x) & GET_MODE_MASK (mode)); - else if (GET_CODE (x) == CONST_INT) - { - if (HOST_BITS_PER_WIDE_INT <= BITS_PER_WORD) - return const0_rtx; - return GEN_INT (INTVAL (x) >> (HOST_BITS_PER_WIDE_INT - BITS_PER_WORD)); - } - else if (GET_CODE (x) == MEM) - { - register int offset = 0; - if (! WORDS_BIG_ENDIAN) - offset = (MAX (xsize, UNITS_PER_WORD) - - MAX (msize, UNITS_PER_WORD)); + result = simplify_gen_subreg (mode, x, GET_MODE (x), + subreg_highpart_offset (mode, GET_MODE (x))); + if (!result) + abort (); + return result; +} +/* Return offset in bytes to get OUTERMODE low part + of the value in mode INNERMODE stored in memory in target format. */ - if (! BYTES_BIG_ENDIAN - && msize < UNITS_PER_WORD) - offset -= (msize - MIN (UNITS_PER_WORD, xsize)); +unsigned int +subreg_lowpart_offset (outermode, innermode) + enum machine_mode outermode, innermode; +{ + unsigned int offset = 0; + int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode)); - return change_address (x, mode, plus_constant (XEXP (x, 0), offset)); - } - else if (GET_CODE (x) == SUBREG) + if (difference > 0) { - /* The only time this should occur is when we are looking at a - multi-word item with a SUBREG whose mode is the same as that of the - item. It isn't clear what we would do if it wasn't. */ - if (SUBREG_BYTE (x) != 0) - abort (); - return gen_highpart (mode, SUBREG_REG (x)); + if (WORDS_BIG_ENDIAN) + offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + offset += difference % UNITS_PER_WORD; } - else if (GET_CODE (x) == REG) - { - int offset = 0; - - if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode)) - abort (); - - if ((! WORDS_BIG_ENDIAN || ! BYTES_BIG_ENDIAN) - && xsize > msize) - { - int difference = xsize - msize; - if (! WORDS_BIG_ENDIAN) - offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; - if (! BYTES_BIG_ENDIAN) - offset += difference % UNITS_PER_WORD; - } - if (REGNO (x) < FIRST_PSEUDO_REGISTER) - { - int final_regno = REGNO (x) + - subreg_regno_offset (REGNO (x), GET_MODE (x), offset, mode); - - /* integrate.c can't handle parts of a return value register. - ??? Then integrate.c should be fixed! - ??? What about CLASS_CANNOT_CHANGE_SIZE? */ - if ((! REG_FUNCTION_VALUE_P (x) - || ! rtx_equal_function_value_matters) - /* We want to keep the stack, frame, and arg pointers special. */ - && x != frame_pointer_rtx -#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM - && x != arg_pointer_rtx -#endif - && x != stack_pointer_rtx) - return gen_rtx_REG (mode, final_regno); - } - /* Just generate a normal SUBREG. */ - return gen_rtx_SUBREG (mode, x, offset); - } - else - abort (); + return offset; } -/* Return 1 iff (SUBREG:outermode (OP:innermode) byte) - refers to the least significant part of its containing reg. */ -int -subreg_lowpart_parts_p (outermode, innermode, byte) +/* Return offset in bytes to get OUTERMODE high part + of the value in mode INNERMODE stored in memory in target format. */ +unsigned int +subreg_highpart_offset (outermode, innermode) enum machine_mode outermode, innermode; - unsigned int byte; { unsigned int offset = 0; int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode)); + if (GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode)) + abort (); + if (difference > 0) { - if (WORDS_BIG_ENDIAN) + if (! WORDS_BIG_ENDIAN) offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; - if (BYTES_BIG_ENDIAN) + if (! BYTES_BIG_ENDIAN) offset += difference % UNITS_PER_WORD; } - return byte == offset; + return offset; } /* Return 1 iff X, assumed to be a SUBREG, @@ -1313,8 +1190,8 @@ subreg_lowpart_p (x) else if (GET_MODE (SUBREG_REG (x)) == VOIDmode) return 0; - return subreg_lowpart_parts_p (GET_MODE (x), GET_MODE (SUBREG_REG (x)), - SUBREG_BYTE (x)); + return (subreg_lowpart_offset (GET_MODE (x), GET_MODE (SUBREG_REG (x))) + == SUBREG_BYTE (x)); } diff --git a/gcc/rtl.h b/gcc/rtl.h index 648aa13..1cc0d73 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1198,9 +1198,10 @@ extern rtx constant_subword PARAMS ((rtx, int, extern rtx operand_subword_force PARAMS ((rtx, unsigned int, enum machine_mode)); extern int subreg_lowpart_p PARAMS ((rtx)); -extern int subreg_lowpart_parts_p PARAMS ((enum machine_mode, - enum machine_mode, - unsigned int)); +extern unsigned int subreg_lowpart_offset PARAMS ((enum machine_mode, + enum machine_mode)); +extern unsigned int subreg_highpart_offset PARAMS ((enum machine_mode, + enum machine_mode)); extern rtx make_safe_from PARAMS ((rtx, rtx)); extern rtx convert_memory_address PARAMS ((enum machine_mode, rtx)); extern rtx get_insns PARAMS ((void)); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index af0f81f..0f0f6cd 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -2258,40 +2258,9 @@ replace_regs (x, reg_map, nregs, replace_dest) && GET_CODE (reg_map[REGNO (SUBREG_REG (x))]) == SUBREG) { rtx map_val = reg_map[REGNO (SUBREG_REG (x))]; - rtx map_inner = SUBREG_REG (map_val); - - if (GET_MODE (x) == GET_MODE (map_inner)) - return map_inner; - else - { - int final_offset = SUBREG_BYTE (x) + SUBREG_BYTE (map_val); - - /* When working with REG SUBREGs the rule is that the byte - offset must be a multiple of the SUBREG's mode. */ - final_offset = (final_offset / GET_MODE_SIZE (GET_MODE (x))); - final_offset = (final_offset * GET_MODE_SIZE (GET_MODE (x))); - - /* We cannot call gen_rtx here since we may be linked with - genattrtab.c. */ - /* Let's try clobbering the incoming SUBREG and see - if this is really safe. */ - SUBREG_REG (x) = map_inner; - SUBREG_BYTE (x) = final_offset; - return x; -#if 0 - rtx new = rtx_alloc (SUBREG); - int final_offset = SUBREG_BYTE (x) + SUBREG_BYTE (map_val); - - /* When working with REG SUBREGs the rule is that the byte - offset must be a multiple of the SUBREG's mode. */ - final_offset = (final_offset / GET_MODE_SIZE (GET_MODE (x))); - final_offset = (final_offset * GET_MODE_SIZE (GET_MODE (x))); - - PUT_MODE (new, GET_MODE (x)); - SUBREG_REG (new) = map_inner; - SUBREG_BYTE (new) = final_offset; -#endif - } + return simplify_gen_subreg (GET_MODE (x), map_val, + GET_MODE (SUBREG_REG (x)), + SUBREG_BYTE (x)); } break; diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 621bd90..aef9b55 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -2215,7 +2215,7 @@ simplify_subreg (outermode, op, innermode, byte) Later it we should move all simplification code here and rewrite GEN_LOWPART_IF_POSSIBLE, GEN_HIGHPART, OPERAND_SUBWORD and friends using SIMPLIFY_SUBREG. */ - if (subreg_lowpart_parts_p (outermode, innermode, byte)) + if (subreg_lowpart_offset (outermode, innermode) == byte) { rtx new = gen_lowpart_if_possible (outermode, op); if (new) @@ -2347,11 +2347,23 @@ simplify_subreg (outermode, op, innermode, byte) frame, or argument pointer, leave this as a SUBREG. */ if (REG_P (op) + && (! REG_FUNCTION_VALUE_P (op) + || ! rtx_equal_function_value_matters) +#ifdef CLASS_CANNOT_CHANGE_MODE + && ! (CLASS_CANNOT_CHANGE_MODE_P (outermode, innermode) + && GET_MODE_CLASS (innermode) != MODE_COMPLEX_INT + && GET_MODE_CLASS (innermode) != MODE_COMPLEX_FLOAT + && (TEST_HARD_REG_BIT + (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], + REGNO (op)))) +#endif && REGNO (op) < FIRST_PSEUDO_REGISTER - && REGNO (op) != FRAME_POINTER_REGNUM + && ((reload_completed && !frame_pointer_needed) + || (REGNO (op) != FRAME_POINTER_REGNUM #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM - && REGNO (op) != HARD_FRAME_POINTER_REGNUM + && REGNO (op) != HARD_FRAME_POINTER_REGNUM #endif + )) #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && REGNO (op) != ARG_POINTER_REGNUM #endif @@ -2360,7 +2372,11 @@ simplify_subreg (outermode, op, innermode, byte) int final_regno = subreg_hard_regno (gen_rtx_SUBREG (outermode, op, byte), 0); - if (HARD_REGNO_MODE_OK (final_regno, outermode)) + /* ??? We do allow it if the current REG is not valid for + its mode. This is a kludge to work around how float/complex + arguments are passed on 32-bit Sparc and should be fixed. */ + if (HARD_REGNO_MODE_OK (final_regno, outermode) + || ! HARD_REGNO_MODE_OK (REGNO (op), innermode)) return gen_rtx_REG (outermode, final_regno); }