This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Bad mode-change inside subreg: DImode to SImode


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]