[gnu.gcc.bug] gcc-1.36 DecStation 3100 bug

ham@Neon.Stanford.EDU (Peter R. Ham) (12/15/89)

On the DecStation, immediate constants are limited to 16 bits where
the highest bit is sign extended.

gcc generates some immediate constants that are too large.
Unfortunately, a bug in the mips as doesn't generate an error, but
instead treats large positive constants as negative ones.

Enclosed is a test case, sample run, and resulting assembly.

main()
{
  char* s[0xfffff];
}

32 Huey.Stanford.EDU> gcc -v -S -O big.c
gcc version 1.36
 /usr/local/lib/gcc-cpp -v -undef -D__GNUC__ -Dmips -Dunix -Dultrix -D__mips__ -D__unix__ -D__ultrix__ -D__OPTIMIZE__ -DR3000 -DLANGUAGE_C -DMIPSEL -DSYSTYPE_BSD big.c /usr/tmp/cca00609.cpp
GNU CPP version 1.36
 /usr/local/lib/gcc-cc1 /usr/tmp/cca00609.cpp -O -fstrength-reduce -fomit-frame-pointer -quiet -dumpbase big.c -O -version -o big.s
GNU C version 1.36 (MIPS 1.10) <DECStation>
 compiled by GNU C version 1.36.
default target switches: -munix -mnofixed-ovfl -mG0 -mG1

 #	.verstamp	2 0
gcc_compiled.:
.text
	.align 2
	.globl main
	.ent	main
main:
	subu	$29,4194312	# saveregs=    8
	.frame	$30,0,$31
	.mask	0x40000000,-4194308
	sw	$30,4($29)
	addiu	$30,$29,4194312	# define fp
	addu	$8,$0,$30	# don't trust sp?
	lw	$30,-4194308($8)
	addu	$29,$0,$8	# sp not trusted  here 
	j	$31
 	.end	main
--
Peter Ham			PO Box 3430	(h)(415) 322-4390
MS Computer Science Student	Stanford, CA	ham@cs.stanford.edu
Stanford University 		94309		(o)(415) 723-2067

grunwald@FOOBAR.COLORADO.EDU (Dirk Grunwald) (12/16/89)

In-reply-to: ham@Neon.Stanford.EDU's message of 15 Dec 89 00:22:29 GMT

1.37beta produces the same output, however, I don't think it's wrong.
If you assemble & disassemble the source, you get:

  [foo.s:  10] 0x0:     3c010040        lui     at,0x40
  [foo.s:  10] 0x4:     34210010        ori     at,at,0x10
  [foo.s:  10] 0x8:     03a1e823        subu    sp,sp,at
  [foo.s:  11] 0xc:     afbe0000        sw      s8,0(sp)
  [foo.s:  13] 0x10:    3c0f0040        lui     t7,0x40
  [foo.s:  14] 0x14:    35ef0010        ori     t7,t7,0x10
  [foo.s:  15] 0x18:    03aff021        addu    s8,sp,t7
  [foo.s:  18] 0x1c:    001e4021        addu    t0,zero,s8
  [foo.s:  20] 0x20:    3c1effc0        lui     s8,0xffc0
  [foo.s:  20] 0x24:    03c8f021        addu    s8,s8,t0
  [foo.s:  20] 0x28:    8fdefff0        lw      s8,-16(s8)
  [foo.s:  23] 0x2c:    03e00008        jr      ra
  [foo.s:  22] 0x30:    0008e821        addu    sp,zero,t0

the MIPS assembler quietly converts insns like
	subu	$29,4194312	# saveregs=    8
into
  [foo.s:  10] 0x0:     3c010040        lui     at,0x40
  [foo.s:  10] 0x4:     34210010        ori     at,at,0x10
  [foo.s:  10] 0x8:     03a1e823        subu    sp,sp,at

the 'lui' insn loads the upper half of 'at'(..a temporary register
allocated to the assembler for just this purpose) , clearing the lower
half and the 'ori' sets the lower half.

when you reach the 'subu' you'll have 0x400010 in the at register; the
subtract should then work as expected.

Perhaps the MIPS backend should be changed to do these things
explicitly, I dunno. It might allow more optimizations (sharing of
similar high parts, etc) than the current scheme.

Dirk Grunwald -- Univ. of Colorado at Boulder	(grunwald@foobar.colorado.edu)
						(grunwald@boulder.colorado.edu)