Path: utzoo!telly!ddsw1!lll-winken!uunet!tut.cis.ohio-state.edu!nsc.nsc.com!rfg From: rfg@nsc.nsc.com (Ron Guilmette) Newsgroups: gnu.gcc.bug Subject: (mostly) benign bug in global-alloc.c (GCC 1.30) Message-ID: <8810262257.AA08272@nsc.NSC.COM> Date: 26 Oct 88 22:57:12 GMT Sender: daemon@tut.cis.ohio-state.edu Distribution: gnu Organization: GNUs Not Usenet Lines: 128 BUG in GCC 1.30 -- suggested fix included below In GCC 1.30 (and GCC 1.29) there is an insidious little bug which is apparently benign in most circumstances, but which can wreak havoc on some machines and with some native compilers used for bootstraping GCC (e.g. The GNX 3.X C compiler). It seems that GCC somtimes tries to put 2 word (8-byte) struct's into registers. Then, when it needs to access one of the fields of the struct in question, it has to calculate the REGNO which holds the field in question. This happens in global-alloc.c in the set_preference() function. Unfortunately, the offset calculation there is screwy, so that it sometimes ends up yielding a (-1) offset. If this gets added to a (base) REGNO value which ahppens to be ZERO then you end up with a REGNO of -1. This incorrect REGNO is then used as a shift count to set a bit in one of the entries in the table of bit-arrays called hard_reg_preferences. NOTE THAT THE INCORRECT NEGATIVE REGNO APPEARS ON BOTH A NATIONAL VME532 AND ON THE SEQUENT-BALANCE. You can see it happen if you use the stage1 compiler to recompile either of the files {stmt.c or expr.c} from GCC 1.30. God only knows what other machines this happens on! Now ANSI says that if you do: x |= (1 << (-1)); that the result is undefined. Apparently, the Sequent-Balance C compiler causes something entirely benign to happen with this shift count, but, due to a bug in our native GNX C compiler, all sorts of screwy things happen when shifts counts outside of the range (0 <= N <= 31) are used. Anyway it is just plain wrong to use the negative shift count anyway so it should be fixed. The following patches prevent the negative REGNO's from being calculated and they make the code a bit clearer anyway. diff -rc2 1.30/global-alloc.c 1.30-gnx/global-alloc.c *** 1.30/global-alloc.c Sat Oct 8 10:06:43 1988 --- 1.30-gnx/global-alloc.c Wed Oct 26 12:18:08 1988 *************** *** 890,894 { int src_regno, dest_regno; ! /* Amount to add to the hard regno for SRC, or subtract from that for DEST, to compensate for subregs in SRC or DEST. */ int offset = 0; --- 890,894 ----- { int src_regno, dest_regno; ! /* Amount to add to the hard regno for SRC or DEST to compensate for subregs in SRC or DEST. */ int src_offset = 0, dest_offset = 0; *************** *** 892,896 /* Amount to add to the hard regno for SRC, or subtract from that for DEST, to compensate for subregs in SRC or DEST. */ ! int offset = 0; if (GET_RTX_FORMAT (GET_CODE (src))[0] == 'e') --- 892,896 ----- /* Amount to add to the hard regno for SRC or DEST to compensate for subregs in SRC or DEST. */ ! int src_offset = 0, dest_offset = 0; if (GET_RTX_FORMAT (GET_CODE (src))[0] == 'e') *************** *** 905,909 { src_regno = REGNO (SUBREG_REG (src)); ! offset += SUBREG_WORD (src); } else --- 905,909 ----- { src_regno = REGNO (SUBREG_REG (src)); ! src_offset = SUBREG_WORD (src); } else *************** *** 915,919 { dest_regno = REGNO (SUBREG_REG (dest)); ! offset -= SUBREG_WORD (dest); } else --- 915,919 ----- { dest_regno = REGNO (SUBREG_REG (dest)); ! dest_offset = SUBREG_WORD (dest); } else *************** *** 934,938 && reg_allocno[src_regno] >= 0) { ! dest_regno -= offset; SET_REGBIT (hard_reg_preferences, reg_allocno[src_regno], dest_regno); SET_HARD_REG_BIT (regs_someone_prefers, dest_regno); --- 934,940 ----- && reg_allocno[src_regno] >= 0) { ! dest_regno += dest_offset; ! if ((dest_regno < 0) || (dest_regno >= FIRST_PSEUDO_REGISTER)) ! abort (); SET_REGBIT (hard_reg_preferences, reg_allocno[src_regno], dest_regno); SET_HARD_REG_BIT (regs_someone_prefers, dest_regno); *************** *** 942,946 && reg_allocno[dest_regno] >= 0) { ! src_regno += offset; SET_REGBIT (hard_reg_preferences, reg_allocno[dest_regno], src_regno); SET_HARD_REG_BIT (regs_someone_prefers, src_regno); --- 944,948 ----- && reg_allocno[dest_regno] >= 0) { ! src_regno += src_offset; SET_REGBIT (hard_reg_preferences, reg_allocno[dest_regno], src_regno); SET_HARD_REG_BIT (regs_someone_prefers, src_regno);