This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Bad mode-change inside subreg: DImode to SImode
- From: Julian Brown <brown at cs dot bris dot ac dot uk>
- To: gcc at gcc dot gnu dot org
- Date: Sat, 13 Mar 2004 19:38:14 +0000 (UTC)
- Subject: Bad mode-change inside subreg: DImode to SImode
- Organization: University of Bristol
- Reply-to: brown at cs dot bris dot ac dot uk
Hi,
I am working on a port of GCC to a custom architecture, and I have
hit a problem recently (possibly since starting working against newer
versions of GCC) which I am having particular difficulty in solving. I
am working against the gcc-3_4-branch, but the same thing happens with
other recent branches.
The following code refuses to compile:
--
typedef struct {
long long rem;
long long quot;
} lldiv_t;
lldiv_t divlong (long long numer, long long denom)
{
lldiv_t retval;
if (numer >= 0) {
retval.quot++;
}
return (retval);
}
--
giving the error:
divbug.c: In function `divlong':
divbug.c:14: internal compiler error: in simplify_subreg, at
simplify-rtx.c:3236
I have tracked this down for starters to the cse pass: beforehand, the
offending rtx looks like (from divbug.c.04.jump):
(insn 12 6 13 0 (set (reg:SI 137)
(lt:SI (subreg:SI (reg/v:DI 135 [ numer ]) 4)
(const_int 0 [0x0]))) -1 (nil)
(nil))
and afterwards (divbug.c.06.cse):
(insn 12 6 13 0 (set (reg:SI 137)
(lt:SI (subreg:SI (reg/f:SI 134) 4)
(const_int 0 [0x0]))) 60 {*slt_insn} (nil)
(nil))
The problem is that that substitution is invalid, since (reg/f:SI 134)
doesn't have a second word. Now, I found where the bad substitution is
happening, in canon_reg() in cse.c, which is line 2805 in my version of
the code, the "else" part of:
--
/* If replacing pseudo with hard reg or vice versa, ensure the
insn remains valid. Likewise if the insn has MATCH_DUPs.
*/
if (insn != 0 && new != 0
&& GET_CODE (new) == REG && GET_CODE (XEXP (x, i)) == REG
&& (((REGNO (new) < FIRST_PSEUDO_REGISTER)
!= (REGNO (XEXP (x, i)) < FIRST_PSEUDO_REGISTER))
|| (insn_code = recog_memoized (insn)) < 0
|| insn_data[insn_code].n_dups > 0))
validate_change (insn, &XEXP (x, i), new, 1);
else
XEXP (x, i) = new;
--
Now though, I am totally stuck trying to figure out why gcc would believe
the substitution to be a sensible thing to do. My speculations are:
(1) There is a structure-sharing violation somehow, and the whole
(subreg...) should have been changed to the (reg...) rather than just
the child pointer changing.
(2) There's a random bug somewhere in my machine description, etc.
which is triggering this behaviour.
I can compile the code with an ARM cross-compiler, and the equivalent
substitution doesn't appear to happen (the rtl isn't identical though,
since my arch has significant differences to the ARM).
I don't have much belief in my ability to decipher exactly what's going
on in cse.c, since it's big & complicated & I'm not that smart. Can
anyone lend any pointers as to what might be happening here?
(My machine description files are at:
http://panic.cs.bris.ac.uk/~jules/dop{.md,.c,.h,-protos.h})
Cheers,
Julian