nfs@notecnirp.Princeton.EDU (Norbert Schlenker) (07/24/89)
I have just spent about two hours trying to make Terrence Holm's
integer calculator (ic(1), from 412@ubc-bdcvax.uucp) work on my system.
What a frustrating experience! And it's not because the calculator
is wrong, either. The compiler shipped with v1.3 is BROKEN (but you
knew that already, didn't you?).
Here is a description of the bugs that I found while trying to make ic
work. Both involve long signed integers.
#1. Generating -2147483648 (the largest negative long integer)
The compiler generates incorrect code for this, IF it is a static or
external variable. Automatics and constants seem fine. Here's an example:
static long int x = 0x80000000;
long int y = 020000000000;
void func()
{
long int a = 0x80000000;
long int b = 020000000000;
long int c;
c = 0x80000000;
func2(c, 0x80000000);
}
Here is the generated code:
.data
_x:
.word 0,-32767
.globl _y
_y:
.word 0,-32767
.globl _func
.text
_func:
push bp
mov bp,sp
sub sp,#12
mov -4(bp),#0
mov -2(bp),#-32768
mov -8(bp),#0
mov -6(bp),#-32768
mov -12(bp),#0
mov -10(bp),#-32768
mov ax,#-32768
push ax
xor ax,ax
push ax
push -10(bp)
push -12(bp)
call _func2
add sp,#8
jmp .cret
Note that the automatic variables a,b, and c are all fine. The
constant passed to func2() is fine too. But x and y are both
initialized to bogus values.
#2. Wrong code is generated for negation of long signed integers
Consider the code:
main()
{
long int x = 65536;
x = -x;
x++;
x = -x;
printf("%ld\n", x);
}
The corresponding assembler is:
.globl _main
.text
_main:
push bp
mov bp,sp
push ax
push ax
mov -4(bp),#0
mov -2(bp),#1
neg -4(bp)
neg -2(bp)
sbb -2(bp),#0
add -4(bp),#1
adc -2(bp),#0
neg -4(bp)
neg -2(bp)
sbb -2(bp),#0
push -2(bp)
push -4(bp)
mov ax,#_1
push ax
call _printf
add sp,#6
jmp .cret
.data
_1:
.word 27685
.word 2660
.word 0
.text
The output is:
131071
which is quite clearly wrong. It should be 65535.
The problem is with the generated code for the negation of a long
integer. The Minix C compiler generates the instruction sequence:
neg loword
neg hiword
sbb hiword,#0
which gives the spurious answer above. It should generate:
neg loword
adc hiword,#0
neg hiword
#3. _doprintf is broken for long integers
This isn't a compiler problem - it's just the truth. The fact that the
compiler is broken makes it that much harder to write a working version.
(The fact that _doprintf doesn't work makes it hard to find compiler bugs!)
No version that I have seen (even one fixed as in 396@uvicctr.uucp) will
correctly handle the case of -2147483648. And the second bug described
above sure makes a lot of other cases fail too (just try -65536 and -655360
in %ld format for fun).
Does anyone have a working _doprintf? Do I need to hack one myself?
Norbert
P.S. (to ast) Do I get a fixed compiler for free? :-)