This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: Reload bug
> > The code is wrong for post-SUBREG_BYTE patch as it checks that the
> > partial regs have exactly size of one word, but we do allow subregs on
> > registers of different sizes. We need to verify that offset can
> > represent the register exactly.
>
> Is it really wrong or is it incomplete now, in the post-SUBREG_BYTE era?
Hi,
this is the patch I am currently playing with. The
subreg_offset_representable_p should return false when we can't
represent the subreg and should abort in the cases I believe current
implemetnation would get entirely confused. I am not quite sure I got
it right, but you may want to take a look :)
Index: emit-rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v
retrieving revision 1.318
diff -c -3 -p -r1.318 emit-rtl.c
*** emit-rtl.c 4 Apr 2003 22:44:02 -0000 1.318
--- emit-rtl.c 11 Apr 2003 18:06:01 -0000
*************** subreg_hard_regno (x, check_mode)
*** 1080,1086 ****
abort ();
if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)))
abort ();
!
/* Catch non-congruent offsets too. */
byte_offset = SUBREG_BYTE (x);
if ((byte_offset % GET_MODE_SIZE (mode)) != 0)
--- 1080,1090 ----
abort ();
if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)))
abort ();
! #ifdef ENABLE_CHECKING
! if (!subreg_offset_representable_p (REGNO (reg), GET_MODE (reg),
! SUBREG_BYTE (x), mode))
! abort ();
! #endif
/* Catch non-congruent offsets too. */
byte_offset = SUBREG_BYTE (x);
if ((byte_offset % GET_MODE_SIZE (mode)) != 0)
Index: reload.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload.c,v
retrieving revision 1.211
diff -c -3 -p -r1.211 reload.c
*** reload.c 26 Mar 2003 07:48:13 -0000 1.211
--- reload.c 11 Apr 2003 18:06:01 -0000
*************** find_reloads (insn, replace, ind_levels,
*** 2880,2885 ****
--- 2880,2891 ----
if (GET_CODE (SUBREG_REG (operand)) == REG
&& REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER)
{
+ if (!subreg_offset_representable_p
+ (REGNO (SUBREG_REG (operand)),
+ GET_MODE (SUBREG_REG (operand)),
+ SUBREG_BYTE (operand),
+ GET_MODE (operand)))
+ force_reload = 1;
offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)),
GET_MODE (SUBREG_REG (operand)),
SUBREG_BYTE (operand),
*************** find_reloads (insn, replace, ind_levels,
*** 2935,2960 ****
)
#endif
)
- /* This following hunk of code should no longer be
- needed at all with SUBREG_BYTE. If you need this
- code back, please explain to me why so I can
- fix the real problem. -DaveM */
- #if 0
- /* Subreg of a hard reg which can't handle the subreg's mode
- or which would handle that mode in the wrong number of
- registers for subregging to work. */
- || (GET_CODE (operand) == REG
- && REGNO (operand) < FIRST_PSEUDO_REGISTER
- && ((GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
- && (GET_MODE_SIZE (GET_MODE (operand))
- > UNITS_PER_WORD)
- && ((GET_MODE_SIZE (GET_MODE (operand))
- / UNITS_PER_WORD)
- != HARD_REGNO_NREGS (REGNO (operand),
- GET_MODE (operand))))
- || ! HARD_REGNO_MODE_OK (REGNO (operand) + offset,
- operand_mode[i])))
- #endif
)
force_reload = 1;
}
--- 2941,2946 ----
*************** find_reloads_address_1 (mode, x, context
*** 5271,5276 ****
--- 5257,5275 ----
GET_MODE (SUBREG_REG (orig_op1)),
SUBREG_BYTE (orig_op1),
GET_MODE (orig_op1))));
+ }
+ /* Plus in the index register may be created only as a result of
+ register remateralization for expresion like &localvar*4. Reload it.
+ It may be possible to combine the displacement on the outer level,
+ but it is probably not worthwhile to do so. */
+ if (context)
+ {
+ find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
+ opnum, ADDR_TYPE (type), ind_levels, insn);
+ push_reload (*loc, NULL_RTX, loc, (rtx*) 0,
+ (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)),
+ GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+ return 1;
}
if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
+ nregs_ymode = HARD_REGNO_NREGS (xregno, ymode);
+
+ /* paradoxical subregs are always valid. */
+ if (offset == 0
+ && nregs_ymode > nregs_xmode
+ && (GET_MODE_SIZE (ymode) > UNITS_PER_WORD
+ ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN))
+ return true;
+
+ /* Lowpart subregs are always valid. */
+ if (offset == subreg_lowpart_offset (ymode, xmode))
+ return true;
+
+ #ifdef ENABLE_CHECKING
+ /* This should always pass, otherwise we don't know how to verify the
+ constraint.
+
+ These conditions may be relaxed but subreg_offset would need to be
+ redesigned. */
+ if (GET_MODE_SIZE (xmode) % GET_MODE_SIZE (ymode)
+ || GET_MODE_SIZE (ymode) % nregs_ymode
+ || mode_for_size (GET_MODE_SIZE (ymode) / nregs_ymode,
+ MODE_INT, 0) == VOIDmode
+ || nregs_xmode % nregs_ymode)
+ abort ();
+ #endif
+
+ /* The XMODE value can be seen as an vector of NREGS_XMODE
+ values. The subreg must represent an lowpart of given field.
+ Compute what field it is. */
+ offset -= subreg_lowpart_offset (mode_for_size (GET_MODE_SIZE (ymode)
+ / nregs_ymode,
+ MODE_INT, 0), xmode);
+
+ /* size of ymode must not be greater than the size of xmode. */
+ mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode);
+ if (mode_multiple == 0)
+ abort ();
+
+ y_offset = offset / GET_MODE_SIZE (ymode);
+ nregs_multiple = nregs_xmode / nregs_ymode;
+ #ifdef ENABLE_CHECKING
+ if (offset % GET_MODE_SIZE (ymode)
+ || mode_multiple % nregs_multiple)
+ abort ();
+ #endif
+ return (!(y_offset % (mode_multiple / nregs_multiple)));
+ }
+
/* Return the final regno that a subreg expression refers to. */
unsigned int
subreg_regno (x)