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? :-)