From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2479 invoked by alias); 17 Nov 2004 18:40:38 -0000 Mailing-List: contact gcc-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Archive: List-Post: List-Help: Sender: gcc-owner@gcc.gnu.org Received: (qmail 2252 invoked from network); 17 Nov 2004 18:40:15 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by sourceware.org with SMTP; 17 Nov 2004 18:40:15 -0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.12.11/8.12.11) with ESMTP id iAHIeFWB008920 for ; Wed, 17 Nov 2004 13:40:15 -0500 Received: from potter.sfbay.redhat.com (potter.sfbay.redhat.com [172.16.27.15]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id iAHIeDr16993 for ; Wed, 17 Nov 2004 13:40:13 -0500 Received: from frothingslosh.sfbay.redhat.com (frothingslosh.sfbay.redhat.com [172.16.24.27]) by potter.sfbay.redhat.com (8.12.8/8.12.8) with ESMTP id iAHIeAcv010877 for ; Wed, 17 Nov 2004 13:40:11 -0500 Received: from frothingslosh.sfbay.redhat.com (localhost.localdomain [127.0.0.1]) by frothingslosh.sfbay.redhat.com (8.13.1/8.13.1) with ESMTP id iAHIe9bY012274 for ; Wed, 17 Nov 2004 10:40:09 -0800 Received: (from rth@localhost) by frothingslosh.sfbay.redhat.com (8.13.1/8.13.1/Submit) id iAHIe90L012273 for gcc@gcc.gnu.org; Wed, 17 Nov 2004 10:40:09 -0800 X-Authentication-Warning: frothingslosh.sfbay.redhat.com: rth set sender to rth@redhat.com using -f Date: Wed, 17 Nov 2004 18:58:00 -0000 From: Richard Henderson To: gcc@gcc.gnu.org Subject: [cft] subreg validation round 2 Message-ID: <20041117184009.GA12257@redhat.com> Mail-Followup-To: Richard Henderson , gcc@gcc.gnu.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.1i X-SW-Source: 2004-11/txt/msg00570.txt.bz2 This passes on i686, alpha, ia64, powerpc linux, and sparc-solaris. Given Ulrich's previous testing, it *ought* to pass on s390. Any other takers before I check it in and have to pick up pieces after the fact? r~ Index: caller-save.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/caller-save.c,v retrieving revision 1.69 diff -u -p -r1.69 caller-save.c --- caller-save.c 4 Nov 2004 08:40:56 -0000 1.69 +++ caller-save.c 15 Nov 2004 20:38:43 -0000 @@ -500,8 +500,7 @@ mark_set_regs (rtx reg, rtx setter ATTRI rtx inner = SUBREG_REG (reg); if (!REG_P (inner) || REGNO (inner) >= FIRST_PSEUDO_REGISTER) return; - - regno = subreg_hard_regno (reg, 1); + regno = subreg_regno (reg); } else if (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER) Index: combine.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/combine.c,v retrieving revision 1.460 diff -u -p -r1.460 combine.c --- combine.c 22 Oct 2004 17:05:03 -0000 1.460 +++ combine.c 15 Nov 2004 20:38:43 -0000 @@ -9308,16 +9308,18 @@ recog_for_combine (rtx *pnewpat, rtx ins An insn containing that will not be recognized. */ static rtx -gen_lowpart_for_combine (enum machine_mode mode, rtx x) +gen_lowpart_for_combine (enum machine_mode omode, rtx x) { + enum machine_mode imode = GET_MODE (x); + unsigned int osize = GET_MODE_SIZE (omode); + unsigned int isize = GET_MODE_SIZE (imode); rtx result; - if (GET_MODE (x) == mode) + if (omode == imode) return x; - /* Return identity if this is a CONST or symbolic - reference. */ - if (mode == Pmode + /* Return identity if this is a CONST or symbolic reference. */ + if (omode == Pmode && (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)) @@ -9325,13 +9327,12 @@ gen_lowpart_for_combine (enum machine_mo /* We can only support MODE being wider than a word if X is a constant integer or has a mode the same size. */ - - if (GET_MODE_SIZE (mode) > UNITS_PER_WORD - && ! ((GET_MODE (x) == VOIDmode + if (GET_MODE_SIZE (omode) > UNITS_PER_WORD + && ! ((imode == VOIDmode && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)) - || GET_MODE_SIZE (GET_MODE (x)) == GET_MODE_SIZE (mode))) - return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); + || isize == osize)) + goto fail; /* X might be a paradoxical (subreg (mem)). In that case, gen_lowpart won't know what to do. So we will strip off the SUBREG here and @@ -9339,11 +9340,12 @@ gen_lowpart_for_combine (enum machine_mo if (GET_CODE (x) == SUBREG && MEM_P (SUBREG_REG (x))) { x = SUBREG_REG (x); - if (GET_MODE (x) == mode) + if (GET_MODE (x) == omode) return x; } - result = gen_lowpart_common (mode, x); + result = gen_lowpart_common (omode, x); + #ifdef CANNOT_CHANGE_MODE_CLASS if (result != 0 && GET_CODE (result) == SUBREG) record_subregs_of_mode (result); @@ -9359,33 +9361,28 @@ gen_lowpart_for_combine (enum machine_mo /* Refuse to work on a volatile memory ref or one with a mode-dependent address. */ if (MEM_VOLATILE_P (x) || mode_dependent_address_p (XEXP (x, 0))) - return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); + goto fail; /* If we want to refer to something bigger than the original memref, generate a paradoxical subreg instead. That will force a reload of the original memref X. */ - if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode)) - return gen_rtx_SUBREG (mode, x, 0); + if (isize < osize) + return gen_rtx_SUBREG (omode, x, 0); if (WORDS_BIG_ENDIAN) - offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) - - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)); + offset = MAX (isize, UNITS_PER_WORD) - MAX (osize, UNITS_PER_WORD); + /* Adjust the address so that the address-after-the-data is unchanged. */ 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)))); - } + offset -= MIN (UNITS_PER_WORD, osize) - MIN (UNITS_PER_WORD, isize); - return adjust_address_nv (x, mode, offset); + return adjust_address_nv (x, omode, offset); } /* If X is a comparison operator, rewrite it in a new mode. This probably won't match, but may allow further simplifications. */ else if (COMPARISON_P (x)) - return gen_rtx_fmt_ee (GET_CODE (x), mode, XEXP (x, 0), XEXP (x, 1)); + return gen_rtx_fmt_ee (GET_CODE (x), omode, XEXP (x, 0), XEXP (x, 1)); /* If we couldn't simplify X any other way, just enclose it in a SUBREG. Normally, this SUBREG won't match, but some patterns may @@ -9394,21 +9391,22 @@ gen_lowpart_for_combine (enum machine_mo { int offset = 0; rtx res; - enum machine_mode sub_mode = GET_MODE (x); - offset = subreg_lowpart_offset (mode, sub_mode); - if (sub_mode == VOIDmode) + offset = subreg_lowpart_offset (omode, imode); + if (imode == VOIDmode) { - sub_mode = int_mode_for_mode (mode); - x = gen_lowpart_common (sub_mode, x); - if (x == 0) - return gen_rtx_CLOBBER (VOIDmode, const0_rtx); + imode = int_mode_for_mode (omode); + x = gen_lowpart_common (imode, x); + if (x == NULL) + goto fail; } - res = simplify_gen_subreg (mode, x, sub_mode, offset); + res = simplify_gen_subreg (omode, x, imode, offset); if (res) return res; - return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); } + + fail: + return gen_rtx_CLOBBER (imode, const0_rtx); } /* These routines make binary and unary operations by first seeing if they Index: cse.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cse.c,v retrieving revision 1.322 diff -u -p -r1.322 cse.c --- cse.c 13 Nov 2004 17:11:02 -0000 1.322 +++ cse.c 15 Nov 2004 20:38:43 -0000 @@ -4327,6 +4327,18 @@ record_jump_equiv (rtx insn, int taken) record_jump_cond (code, mode, op0, op1, reversed_nonequality); } +/* Yet another form of subreg creation. In this case, we want something in + MODE, and we should assume OP has MODE iff it is naturally modeless. */ + +static rtx +record_jump_cond_subreg (enum machine_mode mode, rtx op) +{ + enum machine_mode op_mode = GET_MODE (op); + if (op_mode == mode || op_mode == VOIDmode) + return op; + return lowpart_subreg (mode, op, op_mode); +} + /* We know that comparison CODE applied to OP0 and OP1 in MODE is true. REVERSED_NONEQUALITY is nonzero if CODE had to be swapped. Make any useful entries we can with that information. Called from @@ -4351,11 +4363,10 @@ record_jump_cond (enum rtx_code code, en > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))) { enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0)); - rtx tem = gen_lowpart (inner_mode, op1); - - record_jump_cond (code, mode, SUBREG_REG (op0), - tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0), - reversed_nonequality); + rtx tem = record_jump_cond_subreg (inner_mode, op1); + if (tem) + record_jump_cond (code, mode, SUBREG_REG (op0), tem, + reversed_nonequality); } if (code == EQ && GET_CODE (op1) == SUBREG @@ -4363,11 +4374,10 @@ record_jump_cond (enum rtx_code code, en > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))))) { enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1)); - rtx tem = gen_lowpart (inner_mode, op0); - - record_jump_cond (code, mode, SUBREG_REG (op1), - tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0), - reversed_nonequality); + rtx tem = record_jump_cond_subreg (inner_mode, op0); + if (tem) + record_jump_cond (code, mode, SUBREG_REG (op1), tem, + reversed_nonequality); } /* Similarly, if this is an NE comparison, and either is a SUBREG @@ -4383,11 +4393,10 @@ record_jump_cond (enum rtx_code code, en < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))) { enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0)); - rtx tem = gen_lowpart (inner_mode, op1); - - record_jump_cond (code, mode, SUBREG_REG (op0), - tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0), - reversed_nonequality); + rtx tem = record_jump_cond_subreg (inner_mode, op1); + if (tem) + record_jump_cond (code, mode, SUBREG_REG (op0), tem, + reversed_nonequality); } if (code == NE && GET_CODE (op1) == SUBREG @@ -4396,11 +4405,10 @@ record_jump_cond (enum rtx_code code, en < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))))) { enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1)); - rtx tem = gen_lowpart (inner_mode, op0); - - record_jump_cond (code, mode, SUBREG_REG (op1), - tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0), - reversed_nonequality); + rtx tem = record_jump_cond_subreg (inner_mode, op0); + if (tem) + record_jump_cond (code, mode, SUBREG_REG (op1), tem, + reversed_nonequality); } /* Hash both operands. */ Index: emit-rtl.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v retrieving revision 1.424 diff -u -p -r1.424 emit-rtl.c --- emit-rtl.c 14 Nov 2004 12:55:15 -0000 1.424 +++ emit-rtl.c 15 Nov 2004 20:38:43 -0000 @@ -607,20 +607,98 @@ gen_const_mem (enum machine_mode mode, r return mem; } +/* We want to create (subreg:OMODE (obj:IMODE) OFFSET). Return true if + this construct would be valid, and false otherwise. */ + +bool +validate_subreg (enum machine_mode omode, enum machine_mode imode, + rtx reg, unsigned int offset) +{ + unsigned int isize = GET_MODE_SIZE (imode); + unsigned int osize = GET_MODE_SIZE (omode); + + /* All subregs must be aligned. */ + if (offset % osize != 0) + return false; + + /* The subreg offset cannot be outside the inner object. */ + if (offset >= isize) + return false; + + /* ??? This should not be here. Temporarily continue to allow word_mode + subregs of anything. The most common offender is (subreg:SI (reg:DF)). + Generally, backends are doing something sketchy but it'll take time to + fix them all. */ + if (omode == word_mode) + ; + /* ??? Similarly, e.g. with (subreg:DF (reg:TI)). Though store_bit_field + is the culprit here, and not the backends. */ + else if (osize >= UNITS_PER_WORD && isize >= osize) + ; + /* Allow component subregs of complex and vector. Though given the below + extraction rules, it's not always clear what that means. */ + else if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode)) + && GET_MODE_INNER (imode) == omode) + ; + /* ??? x86 sse code makes heavy use of *paradoxical* vector subregs, + i.e. (subreg:V4SF (reg:SF) 0). This surely isn't the cleanest way to + represent this. It's questionable if this ought to be represented at + all -- why can't this all be hidden in post-reload splitters that make + arbitrarily mode changes to the registers themselves. */ + else if (VECTOR_MODE_P (omode) && GET_MODE_INNER (omode) == imode) + ; + /* Subregs involving floating point modes are not allowed to + change size. Therefore (subreg:DI (reg:DF) 0) is fine, but + (subreg:SI (reg:DF) 0) isn't. */ + else if (FLOAT_MODE_P (imode) || FLOAT_MODE_P (omode)) + { + if (isize != osize) + return false; + } + + /* Paradoxical subregs must have offset zero. */ + if (osize > isize) + return offset == 0; + + /* This is a normal subreg. Verify that the offset is representable. */ + + /* For hard registers, we already have most of these rules collected in + subreg_offset_representable_p. */ + if (reg && REG_P (reg) && HARD_REGISTER_P (reg)) + { + unsigned int regno = REGNO (reg); + +#ifdef CANNOT_CHANGE_MODE_CLASS + if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode)) + && GET_MODE_INNER (imode) == omode) + ; + else if (REG_CANNOT_CHANGE_MODE_P (regno, imode, omode)) + return false; +#endif + + return subreg_offset_representable_p (regno, imode, offset, omode); + } + + /* For pseudo registers, we want most of the same checks. Namely: + If the register no larger than a word, the subreg must be lowpart. + If the register is larger than a word, the subreg must be the lowpart + of a subword. A subreg does *not* perform arbitrary bit extraction. + Given that we've already checked mode/offset alignment, we only have + to check subword subregs here. */ + if (osize < UNITS_PER_WORD) + { + enum machine_mode wmode = isize > UNITS_PER_WORD ? word_mode : imode; + unsigned int low_off = subreg_lowpart_offset (omode, wmode); + if (offset % UNITS_PER_WORD != low_off) + return false; + } + return true; +} + rtx gen_rtx_SUBREG (enum machine_mode mode, rtx reg, int offset) { - /* This is the most common failure type. - Catch it early so we can see who does it. */ - gcc_assert (!(offset % GET_MODE_SIZE (mode))); - - /* This check isn't usable right now because combine will - throw arbitrary crap like a CALL into a SUBREG in - gen_lowpart_for_combine so we must just eat it. */ -#if 0 - /* Check for this too. */ - gcc_assert (offset < GET_MODE_SIZE (GET_MODE (reg))); -#endif + gcc_assert (validate_subreg (mode, GET_MODE (reg), reg, offset)); return gen_rtx_raw_SUBREG (mode, reg, offset); } @@ -1018,34 +1096,6 @@ maybe_set_first_label_num (rtx x) first_label_num = CODE_LABEL_NUMBER (x); } -/* Return the final regno of X, which is a SUBREG of a hard - register. */ -int -subreg_hard_regno (rtx x, int check_mode) -{ - enum machine_mode mode = GET_MODE (x); - unsigned int byte_offset, base_regno, final_regno; - rtx reg = SUBREG_REG (x); - - /* This is where we attempt to catch illegal subregs - created by the compiler. */ - gcc_assert (GET_CODE (x) == SUBREG && REG_P (reg)); - base_regno = REGNO (reg); - gcc_assert (base_regno < FIRST_PSEUDO_REGISTER); - gcc_assert (!check_mode || HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg))); -#ifdef ENABLE_CHECKING - gcc_assert (subreg_offset_representable_p (REGNO (reg), GET_MODE (reg), - SUBREG_BYTE (x), mode)); -#endif - /* Catch non-congruent offsets too. */ - byte_offset = SUBREG_BYTE (x); - gcc_assert (!(byte_offset % GET_MODE_SIZE (mode))); - - final_regno = subreg_regno (x); - - return final_regno; -} - /* Return a value representing some low-order bits of X, where the number of low-order bits is given by MODE. Note that no conversion is done between floating-point and fixed-point values, rather, the bit Index: expmed.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/expmed.c,v retrieving revision 1.205 diff -u -p -r1.205 expmed.c --- expmed.c 13 Nov 2004 22:10:47 -0000 1.205 +++ expmed.c 15 Nov 2004 20:38:43 -0000 @@ -1233,22 +1233,16 @@ extract_bit_field (rtx str_rtx, unsigned { if (mode1 != GET_MODE (op0)) { - if (GET_CODE (op0) == SUBREG) + if (MEM_P (op0)) + op0 = adjust_address (op0, mode1, offset); + else { - if (GET_MODE (SUBREG_REG (op0)) == mode1 - || GET_MODE_CLASS (mode1) == MODE_INT - || GET_MODE_CLASS (mode1) == MODE_PARTIAL_INT) - op0 = SUBREG_REG (op0); - else - /* Else we've got some float mode source being extracted into - a different float mode destination -- this combination of - subregs results in Severe Tire Damage. */ + rtx sub = simplify_gen_subreg (mode1, op0, GET_MODE (op0), + byte_offset); + if (sub == NULL) goto no_subreg_mode_swap; + op0 = sub; } - if (REG_P (op0)) - op0 = gen_rtx_SUBREG (mode1, op0, byte_offset); - else - op0 = adjust_address (op0, mode1, offset); } if (mode1 != mode) return convert_to_mode (tmode, op0, unsignedp); @@ -1628,19 +1622,41 @@ extract_bit_field (rtx str_rtx, unsigned return spec_target; if (GET_MODE (target) != tmode && GET_MODE (target) != mode) { - /* If the target mode is floating-point, first convert to the - integer mode of that size and then access it as a floating-point - value via a SUBREG. */ - if (GET_MODE_CLASS (tmode) != MODE_INT - && GET_MODE_CLASS (tmode) != MODE_PARTIAL_INT) + /* If the target mode is complex, then extract the two scalar elements + from the value now. Creating (subreg:SC (reg:DI) 0), as we would do + with the clause below, will cause gen_realpart or gen_imagpart to + fail, since those functions must return lvalues. */ + if (COMPLEX_MODE_P (tmode)) { + rtx realpart, imagpart; + enum machine_mode itmode = GET_MODE_INNER (tmode); + target = convert_to_mode (mode_for_size (GET_MODE_BITSIZE (tmode), MODE_INT, 0), target, unsignedp); + + realpart = extract_bit_field (target, GET_MODE_BITSIZE (itmode), 0, + unsignedp, NULL, itmode, itmode); + imagpart = extract_bit_field (target, GET_MODE_BITSIZE (itmode), + GET_MODE_BITSIZE (itmode), unsignedp, + NULL, itmode, itmode); + + return gen_rtx_CONCAT (tmode, realpart, imagpart); + } + + /* If the target mode is not a scalar integral, first convert to the + integer mode of that size and then access it as a floating-point + value via a SUBREG. */ + if (!SCALAR_INT_MODE_P (tmode)) + { + enum machine_mode smode + = mode_for_size (GET_MODE_BITSIZE (tmode), MODE_INT, 0); + target = convert_to_mode (smode, target, unsignedp); + target = force_reg (smode, target); return gen_lowpart (tmode, target); } - else - return convert_to_mode (tmode, target, unsignedp); + + return convert_to_mode (tmode, target, unsignedp); } return target; } Index: expr.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/expr.c,v retrieving revision 1.741 diff -u -p -r1.741 expr.c --- expr.c 14 Nov 2004 13:05:19 -0000 1.741 +++ expr.c 15 Nov 2004 20:38:43 -0000 @@ -2647,7 +2647,6 @@ emit_move_insn_1 (rtx x, rtx y) { enum machine_mode mode = GET_MODE (x); enum machine_mode submode; - enum mode_class class = GET_MODE_CLASS (mode); gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE); @@ -2656,20 +2655,21 @@ emit_move_insn_1 (rtx x, rtx y) emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y)); /* Expand complex moves by moving real part and imag part, if possible. */ - else if ((class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT) + else if (COMPLEX_MODE_P (mode) && BLKmode != (submode = GET_MODE_INNER (mode)) && (mov_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing)) { + unsigned int modesize = GET_MODE_SIZE (mode); + unsigned int submodesize = GET_MODE_SIZE (submode); + /* Don't split destination if it is a stack push. */ - int stack = push_operand (x, GET_MODE (x)); + int stack = push_operand (x, mode); #ifdef PUSH_ROUNDING /* In case we output to the stack, but the size is smaller than the machine can push exactly, we need to use move instructions. */ - if (stack - && (PUSH_ROUNDING (GET_MODE_SIZE (submode)) - != GET_MODE_SIZE (submode))) + if (stack && PUSH_ROUNDING (submodesize) != submodesize) { rtx temp; HOST_WIDE_INT offset1, offset2; @@ -2683,9 +2683,7 @@ emit_move_insn_1 (rtx x, rtx y) add_optab, #endif stack_pointer_rtx, - GEN_INT - (PUSH_ROUNDING - (GET_MODE_SIZE (GET_MODE (x)))), + GEN_INT (PUSH_ROUNDING (modesize)), stack_pointer_rtx, 0, OPTAB_LIB_WIDEN); if (temp != stack_pointer_rtx) @@ -2693,11 +2691,10 @@ emit_move_insn_1 (rtx x, rtx y) #ifdef STACK_GROWS_DOWNWARD offset1 = 0; - offset2 = GET_MODE_SIZE (submode); + offset2 = submodesize; #else - offset1 = -PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x))); - offset2 = (-PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x))) - + GET_MODE_SIZE (submode)); + offset1 = -PUSH_ROUNDING (modesize); + offset2 = -PUSH_ROUNDING (modesize) + submodesize; #endif emit_move_insn (change_address (x, submode, @@ -2748,42 +2745,32 @@ emit_move_insn_1 (rtx x, rtx y) memory and reload. FIXME, we should see about using extract and insert on integer registers, but complex short and complex char variables should be rarely used. */ - if (GET_MODE_BITSIZE (mode) < 2 * BITS_PER_WORD - && (reload_in_progress | reload_completed) == 0) + if ((reload_in_progress | reload_completed) == 0 + && (!validate_subreg (submode, mode, NULL, submodesize) + || !validate_subreg (submode, mode, NULL, 0))) { - int packed_dest_p - = (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER); - int packed_src_p - = (REG_P (y) && REGNO (y) < FIRST_PSEUDO_REGISTER); - - if (packed_dest_p || packed_src_p) + if (REG_P (x) || REG_P (y)) { - enum mode_class reg_class = ((class == MODE_COMPLEX_FLOAT) - ? MODE_FLOAT : MODE_INT); - + rtx mem, cmem; enum machine_mode reg_mode - = mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1); + = mode_for_size (GET_MODE_BITSIZE (mode), MODE_INT, 1); + + gcc_assert (reg_mode != BLKmode); + + mem = assign_stack_temp (reg_mode, modesize, 0); + cmem = adjust_address (mem, mode, 0); - if (reg_mode != BLKmode) + if (REG_P (x)) + { + rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0); + emit_move_insn_1 (cmem, y); + return emit_move_insn_1 (sreg, mem); + } + else { - rtx mem = assign_stack_temp (reg_mode, - GET_MODE_SIZE (mode), 0); - rtx cmem = adjust_address (mem, mode, 0); - - if (packed_dest_p) - { - rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0); - - emit_move_insn_1 (cmem, y); - return emit_move_insn_1 (sreg, mem); - } - else - { - rtx sreg = gen_rtx_SUBREG (reg_mode, y, 0); - - emit_move_insn_1 (mem, sreg); - return emit_move_insn_1 (x, cmem); - } + rtx sreg = gen_rtx_SUBREG (reg_mode, y, 0); + emit_move_insn_1 (mem, sreg); + return emit_move_insn_1 (x, cmem); } } } Index: final.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/final.c,v retrieving revision 1.342 diff -u -p -r1.342 final.c --- final.c 9 Nov 2004 10:12:15 -0000 1.342 +++ final.c 15 Nov 2004 20:38:43 -0000 @@ -2636,8 +2636,7 @@ alter_subreg (rtx *xp) else { /* Simplify_subreg can't handle some REG cases, but we have to. */ - unsigned int regno = subreg_hard_regno (x, 1); - + unsigned int regno = subreg_regno (x); gcc_assert (REG_P (y)); *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, SUBREG_BYTE (x)); } Index: local-alloc.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/local-alloc.c,v retrieving revision 1.141 diff -u -p -r1.141 local-alloc.c --- local-alloc.c 4 Nov 2004 08:41:04 -0000 1.141 +++ local-alloc.c 15 Nov 2004 20:38:43 -0000 @@ -2012,7 +2012,7 @@ reg_is_born (rtx reg, int birth) { regno = REGNO (SUBREG_REG (reg)); if (regno < FIRST_PSEUDO_REGISTER) - regno = subreg_hard_regno (reg, 1); + regno = subreg_regno (reg); } else regno = REGNO (reg); Index: regmove.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/regmove.c,v retrieving revision 1.164 diff -u -p -r1.164 regmove.c --- regmove.c 9 Oct 2004 19:19:24 -0000 1.164 +++ regmove.c 15 Nov 2004 20:38:43 -0000 @@ -1150,10 +1150,8 @@ regmove_optimize (rtx f, int nregs, FILE && GET_MODE_SIZE (GET_MODE (dst)) >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dst)))) { - src_subreg - = gen_rtx_SUBREG (GET_MODE (SUBREG_REG (dst)), - src, SUBREG_BYTE (dst)); dst = SUBREG_REG (dst); + src_subreg = gen_lowpart (GET_MODE (dst), src); } if (!REG_P (dst) || REGNO (dst) < FIRST_PSEUDO_REGISTER) Index: rtl.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/rtl.h,v retrieving revision 1.524 diff -u -p -r1.524 rtl.h --- rtl.h 14 Nov 2004 12:55:15 -0000 1.524 +++ rtl.h 15 Nov 2004 20:38:43 -0000 @@ -1353,7 +1353,6 @@ extern rtx emit_copy_of_insn_after (rtx, extern void set_reg_attrs_from_mem (rtx, rtx); extern void set_mem_attrs_from_reg (rtx, rtx); extern void set_reg_attrs_for_parm (rtx, rtx); -extern void set_reg_pointer_align (rtx, unsigned int); extern int mem_expr_equal_p (tree, tree); /* In rtl.c */ @@ -1377,7 +1376,6 @@ extern rtvec gen_rtvec_v (int, rtx *); extern rtx gen_reg_rtx (enum machine_mode); 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); /* In cse.c */ @@ -1969,6 +1967,8 @@ extern rtx delete_insn_and_edges (rtx); extern void delete_insn_chain_and_edges (rtx, rtx); extern rtx gen_lowpart_SUBREG (enum machine_mode, rtx); extern rtx gen_const_mem (enum machine_mode, rtx); +extern bool validate_subreg (enum machine_mode, enum machine_mode, + rtx, unsigned int); /* In combine.c */ extern int combine_instructions (rtx, unsigned int); Index: simplify-rtx.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v retrieving revision 1.207 diff -u -p -r1.207 simplify-rtx.c --- simplify-rtx.c 28 Oct 2004 12:47:21 -0000 1.207 +++ simplify-rtx.c 15 Nov 2004 20:38:43 -0000 @@ -3641,12 +3641,14 @@ simplify_subreg (enum machine_mode outer } /* Recurse for further possible simplifications. */ - newx = simplify_subreg (outermode, SUBREG_REG (op), - GET_MODE (SUBREG_REG (op)), - final_offset); + newx = simplify_subreg (outermode, SUBREG_REG (op), innermostmode, + final_offset); if (newx) return newx; - return gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset); + if (validate_subreg (outermode, innermostmode, + SUBREG_REG (op), final_offset)) + return gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset); + return NULL_RTX; } /* SUBREG of a hard register => just change the register number @@ -3674,14 +3676,15 @@ simplify_subreg (enum machine_mode outer && subreg_offset_representable_p (REGNO (op), innermode, byte, outermode)) { - rtx tem = gen_rtx_SUBREG (outermode, op, byte); - int final_regno = subreg_hard_regno (tem, 0); + unsigned int regno = REGNO (op); + unsigned int final_regno + = regno + subreg_regno_offset (regno, innermode, byte, 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)) + || ! HARD_REGNO_MODE_OK (regno, innermode)) { rtx x = gen_rtx_REG_offset (op, outermode, final_regno, byte); @@ -3723,9 +3726,9 @@ simplify_subreg (enum machine_mode outer res = simplify_subreg (outermode, part, GET_MODE (part), final_offset); if (res) return res; - /* We can at least simplify it by referring directly to the - relevant part. */ - return gen_rtx_SUBREG (outermode, part, final_offset); + if (validate_subreg (outermode, GET_MODE (part), part, final_offset)) + return gen_rtx_SUBREG (outermode, part, final_offset); + return NULL_RTX; } /* Optimize SUBREG truncations of zero and sign extended values. */ @@ -3773,17 +3776,6 @@ simplify_gen_subreg (enum machine_mode o enum machine_mode innermode, unsigned int byte) { rtx newx; - /* Little bit of sanity checking. */ - gcc_assert (innermode != VOIDmode); - gcc_assert (outermode != VOIDmode); - gcc_assert (innermode != BLKmode); - gcc_assert (outermode != BLKmode); - - gcc_assert (GET_MODE (op) == innermode - || GET_MODE (op) == VOIDmode); - - gcc_assert ((byte % GET_MODE_SIZE (outermode)) == 0); - gcc_assert (byte < GET_MODE_SIZE (innermode)); newx = simplify_subreg (outermode, op, innermode, byte); if (newx) @@ -3793,8 +3785,12 @@ simplify_gen_subreg (enum machine_mode o || (REG_P (op) && REGNO (op) < FIRST_PSEUDO_REGISTER)) return NULL_RTX; - return gen_rtx_SUBREG (outermode, op, byte); + if (validate_subreg (outermode, innermode, op, byte)) + return gen_rtx_SUBREG (outermode, op, byte); + + return NULL_RTX; } + /* Simplify X, an rtx expression. Return the simplified expression or NULL if no simplifications