Subject: C compiler mishandles 'u_long op= long' +FIX (#194) Index: lib/ccom/optable,c10.c,c13.c 2.11BSD Description: Some operations using 'unsigned long' cause the compiler to fail with a "no code table" error. The operations which exhibit this behaviour are all of the assignment form: u_long *= long; u_long /= long; and so on. Also, in some cases the operator is not correctly identified in the error message. The compiler is parsing the program correctly but does not know how to generate code for the specified operation. Repeat-By: Attempt to compile the following test program: ======start unsigned long y; long x; main() { y /= x; x /= y; } ======end If something of the form: Script started on Wed Oct 5 13:55:37 1994 sms.1% cc -S t.c 7: No code table for op 125 8: No code table for op: /=(87) type: 6 sms.2% exit script done on Wed Oct 5 13:55:54 1994 is the result then the bug is present and the patch below should be applied. Note the lack of identifying operator name in the first message. Op 125 is the /= operator for u_long being on the left side of an expression. Fix: Save the following patch to a file - /tmp/p. Then: 0) SAVE the existing compiler - save /lib/{c0,c1} somewhere or make sure you have them on known good backups. 1) cd /usr/src/lib/ccom 2) patch < /tmp/p 3) make 4) make install 5) make clean 6) make 7) make install The extra steps make sure that the compiler is able to rebuild itself (probably not necessary but ...) The changes to 'c13.c' are cosmetic. Numbered comments were placed in several of the lengthy tables to make it easy to find a particular entry. A number of entries in the operator name tables were filled in or corrected. These are useful when debugging the compiler. The main fix is in 'optable' a couple of rules were added in 'cr124' and 'cr86' to handle unsigned longs. These were overlooked when I added the 'u_long' capability last year. Apparently nothing in the rest of the system uses the assignment ops when dealing with unsigned longs otherwise the bug would have shown up during the top level make of the system. The other problem, that of omitting the operator string, was due to new operators being added but the range check not being extended in c10.c. At the same time an available register variable was used in the error handling instead of making repeated structure pointer dereferences (it also shortened the lines and improved readability). A version header (ifdef'd out sccsid string) was added to the three affected modules. The generated code for the test program should look like this (create the .s file with "cc -S t.c"): .comm _y,4 .comm _x,4 .globl _main .text _main: ~~main: jsr r5,csv jbr L1 L2:mov 2+_x,-(sp) mov _x,-(sp) mov $_y,-(sp) jsr pc,ualdiv add $6,sp mov 2+_y,-(sp) mov _y,-(sp) mov $_x,-(sp) jsr pc,aldiv add $6,sp L3:jmp cret L1:jbr L2 .globl .data Updates to 2.11BSD are available via anonymous FTP to ftp.iipo.gtegsc.com - look in the directory /pub/2.11BSD. =============cut here *** /usr/src/lib/ccom/optable.old Sat Jul 3 21:34:31 1993 --- /usr/src/lib/ccom/optable Tue Oct 4 21:17:05 1994 *************** *** 2,7 **** --- 2,10 ---- /* * c code tables-- compile to register */ + #if !defined(lint) && defined(DOSCCS) + static char sccsid[] = "@(#)optable 2.1 (2.11BSD GTE) 10/4/94"; + #endif struct table regtab[] = { {106,cr106}, *************** *** 712,718 **** mov #1+2(R),R+ mov #1(R),R ! /* =*, =<< (for integer multiply, R must be odd) */ cr72: %a,aw %ad,ad --- 715,721 ---- mov #1+2(R),R+ mov #1(R),R ! /* *=, <<= (for integer multiply, R must be odd) */ cr72: %a,aw %ad,ad *************** *** 1163,1178 **** %nul,nul % [l82] ! /* =*, =/, =rem for unsigned long */ cr124: ! %n,nul % [l86] ! /* =*, =/, =rem for longs */ /* Operands of the form &x op y, so stack space is known. */ cr86: %[l86:] %n,nl SS FS jsr pc,I --- 1166,1183 ---- %nul,nul % [l82] ! /* *=, /=, %= for unsigned long */ cr124: ! %n,nl ! %nl,n % [l86] ! /* *=, /=, %= for longs */ /* Operands of the form &x op y, so stack space is known. */ cr86: %[l86:] %n,nl + %n,nul SS FS jsr pc,I *** /usr/src/lib/ccom/c10.c.old Sat Jul 3 21:34:10 1993 --- /usr/src/lib/ccom/c10.c Tue Oct 4 21:15:59 1994 *************** *** 1,7 **** /* ! C compiler, part 2 */ #include "c1.h" #ifdef DEBUG --- 1,11 ---- /* ! * C compiler, part 2 */ + #if !defined(lint) && defined(DOSCCS) + static char sccsid[] = "@(#)c10.c 2.1 (2.11BSD GTE) 10/4/94"; + #endif + #include "c1.h" #ifdef DEBUG *************** *** 9,16 **** #else #define dbprint(op) /* */ #endif - int debug; char maprel[] = { EQUAL, NEQUAL, GREATEQ, GREAT, LESSEQ, LESS, GREATQP, GREATP, LESSEQP, LESSP }; --- 13,21 ---- #else #define dbprint(op) /* */ #endif + static int debug = 0; + char maprel[] = { EQUAL, NEQUAL, GREATEQ, GREAT, LESSEQ, LESS, GREATQP, GREATP, LESSEQP, LESSP }; *************** *** 432,443 **** goto fixup; } } if (tree->t.type == STRUCT) error("Illegal operation on structure"); ! else if (tree->t.op>0 && tree->t.opt.op]) ! error("No code table for op: %s(%d) type: %d", opntab[tree->t.op],tree->t.op,tree->t.type); else ! error("No code table for op %d", tree->t.op); return(reg); } --- 437,451 ---- goto fixup; } } + + r = tree->t.op; if (tree->t.type == STRUCT) error("Illegal operation on structure"); ! else if (r > 0 && r < UASLSHL && opntab[r]) ! error("No code table for op: %s(%d) type: %d", opntab[r], r, ! tree->t.type); else ! error("No code table for op %d", r); return(reg); } *** /usr/src/lib/ccom/c13.c.old Sat Jul 3 21:34:22 1993 --- /usr/src/lib/ccom/c13.c Tue Oct 4 21:16:32 1994 *************** *** 1,12 **** /* * C second pass -- tables */ #include "c1.h" /* * Operator dope table-- see description in c0. */ int opdope[] = { ! 000000, /* EOFC */ 000000, /* ; */ 000000, /* { */ 000000, /* } */ --- 1,17 ---- /* * C second pass -- tables */ + + #if !defined(lint) && defined(DOSCCS) + static char sccsid[] = "@(#)c13.c 2.1 (2.11BSD GTE) 10/4/94"; + #endif + #include "c1.h" /* * Operator dope table-- see description in c0. */ int opdope[] = { ! 000000, /* EOFC (0) */ 000000, /* ; */ 000000, /* { */ 000000, /* } */ *************** *** 16,22 **** 002000, /* ) */ 014201, /* : */ 007001, /* , */ ! 000000, /* field selection */ 000000, /* reverse field selection */ 000001, /* temporary field selection */ 000001, /* int->ptr */ --- 21,27 ---- 002000, /* ) */ 014201, /* : */ 007001, /* , */ ! 000000, /* field selection (10) */ 000000, /* reverse field selection */ 000001, /* temporary field selection */ 000001, /* int->ptr */ *************** *** 25,42 **** 000001, /* field assignment */ 000001, /* >> unsigned */ 000001, /* >>= unsigned */ ! 000000, /* 19 */ ! 000400, /* name */ 000400, /* short constant */ 000400, /* string */ 000400, /* float */ 000400, /* double */ ! 0000400, /* long const */ 000400, /* long const <= 16 bits */ 000400, /* autoi, *r++ */ 000400, /* autod, *--r */ 000400, /* () empty arglist */ ! 034213, /* ++pre */ 034213, /* --pre */ 034213, /* ++post */ 034213, /* --post */ --- 30,47 ---- 000001, /* field assignment */ 000001, /* >> unsigned */ 000001, /* >>= unsigned */ ! 000000, /* keyword */ ! 000400, /* name (20) */ 000400, /* short constant */ 000400, /* string */ 000400, /* float */ 000400, /* double */ ! 000400, /* long const */ 000400, /* long const <= 16 bits */ 000400, /* autoi, *r++ */ 000400, /* autod, *--r */ 000400, /* () empty arglist */ ! 034213, /* ++pre (30) */ 034213, /* --pre */ 034213, /* ++post */ 034213, /* --post */ *************** *** 46,52 **** 034200, /* -un */ 034220, /* ~un */ 036001, /* . (structure reference) */ ! 030101, /* + */ 030001, /* - */ 032101, /* * */ 032001, /* / */ --- 51,57 ---- 034200, /* -un */ 034220, /* ~un */ 036001, /* . (structure reference) */ ! 030101, /* + (40) */ 030001, /* - */ 032101, /* * */ 032001, /* / */ *************** *** 56,62 **** 020161, /* & */ 016161, /* | */ 016161, /* ^ */ ! 036001, /* -> */ 001000, /* int -> double */ 001000, /* double -> int */ 000001, /* && */ --- 61,67 ---- 020161, /* & */ 016161, /* | */ 016161, /* ^ */ ! 036001, /* -> (50) */ 001000, /* int -> double */ 001000, /* double -> int */ 000001, /* && */ *************** *** 66,72 **** 001000, /* long -> double */ 001000, /* integer -> long */ 000000, /* long -> integer */ ! 022005, /* == */ 022005, /* != */ 024005, /* <= */ 024005, /* < */ --- 71,77 ---- 001000, /* long -> double */ 001000, /* integer -> long */ 000000, /* long -> integer */ ! 022005, /* == (60) */ 022005, /* != */ 024005, /* <= */ 024005, /* < */ *************** *** 76,82 **** 024005, /* <=p */ 024005, /* >p */ 024005, /* >=p */ ! 012213, /* += */ 012213, /* -= */ 012213, /* *= */ 012213, /* /= */ --- 81,87 ---- 024005, /* <=p */ 024005, /* >p */ 024005, /* >=p */ ! 012213, /* += (70) */ 012213, /* -= */ 012213, /* *= */ 012213, /* /= */ *************** *** 86,92 **** 012253, /* &= */ 012253, /* |= */ 012253, /* ^= */ ! 012213, /* = */ 030001, /* & for tests */ 032001, /* * (long) */ 032001, /* / (long) */ --- 91,97 ---- 012253, /* &= */ 012253, /* |= */ 012253, /* ^= */ ! 012213, /* = (80) */ 030001, /* & for tests */ 032001, /* * (long) */ 032001, /* / (long) */ *************** *** 95,102 **** 012213, /* *= (long) */ 012213, /* /= (long) */ 012213, /* %= (long) */ ! 000000, /* 89 */ ! 014201, /* ? */ 026061, /* long << */ 012253, /* long <<= */ 000101, /* max */ --- 100,107 ---- 012213, /* *= (long) */ 012213, /* /= (long) */ 012213, /* %= (long) */ ! 000000, /* (89) */ ! 014201, /* question '?' (90) */ 026061, /* long << */ 012253, /* long <<= */ 000101, /* max */ *************** *** 104,144 **** 000101, /* min */ 000101, /* minp */ 000001, /* , */ ! 000000, /* 98 */ ! 000000, /* 99 */ ! 036001, /* call */ 036000, /* mcall */ 000000, /* goto */ 000000, /* jump cond */ 000000, /* branch cond */ 000400, /* set nregs */ ! 000000, /* 106 */ ! 030001, /* 107 */ ! 000000, /* 108 */ 000000, /* int->char */ ! 000000, /* force r0 */ ! 000000, /* 111 */ ! 000000, /* 112 */ ! 000000, /* 113 */ ! 000000, /* 114 */ 000000, /* structure assign */ 000001, /* struct assignment setup */ 032001, /* unsigned / */ 032001, /* unsigned % */ 012213, /* unsigned /= */ ! 012213, /* unsigned %= */ ! 032001, /* 121 unsigned long * */ ! 032001, /* 122 unsigned long / */ ! 032001, /* 123 unsigned long % */ ! 012213, /* 124 unsigned long *= */ ! 012213, /* 125 unsigned long /= */ ! 012213, /* 126 unsigned long %= */ ! 01000, /* 127 unsigned long -> float(double) */ ! 026061, /* 128 unsigned long >> */ ! 012253, /* 129 unsigned long >>= */ }; char *opntab[] = { 0, 0, 0, --- 109,150 ---- 000101, /* min */ 000101, /* minp */ 000001, /* , */ ! 000000, /* call1 */ ! 000000, /* call2 */ ! 036001, /* call (100) */ 036000, /* mcall */ 000000, /* goto */ 000000, /* jump cond */ 000000, /* branch cond */ 000400, /* set nregs */ ! 000000, /* load */ ! 030001, /* ptoi1 */ ! 000000, /* (108) */ 000000, /* int->char */ ! 000000, /* force r0 (110) */ ! 000000, /* branch */ ! 000000, /* label */ ! 000000, /* nlabel */ ! 000000, /* rlabel */ 000000, /* structure assign */ 000001, /* struct assignment setup */ 032001, /* unsigned / */ 032001, /* unsigned % */ 012213, /* unsigned /= */ ! 012213, /* unsigned %= (120) */ ! 032001, /* unsigned long * */ ! 032001, /* unsigned long / */ ! 032001, /* unsigned long % */ ! 012213, /* unsigned long *= */ ! 012213, /* unsigned long /= */ ! 012213, /* unsigned long %= */ ! 01000, /* unsigned long -> float(double) */ ! 026061, /* unsigned long >> */ ! 012253, /* unsigned long >>= (129) */ }; char *opntab[] = { + 0, /* 0 */ 0, 0, 0, *************** *** 146,155 **** 0, 0, 0, - 0, ":", ",", ! "field select", 0, 0, "int->ptr", --- 152,160 ---- 0, 0, 0, ":", ",", ! "field select", /* 10 */ 0, 0, "int->ptr", *************** *** 158,165 **** "field assign", ">>", ">>=", ! 0, ! "name", "short constant", "string", "float", --- 163,170 ---- "field assign", ">>", ">>=", ! "keyword", ! "name", /* 20 */ "short constant", "string", "float", *************** *** 169,175 **** "*r++", "*--r", "()", ! "++pre", "--pre", "++post", "--post", --- 174,180 ---- "*r++", "*--r", "()", ! "++pre", /* 30 */ "--pre", "++post", "--post", *************** *** 179,185 **** "-", "~", ".", ! "+", "-", "*", "/", --- 184,190 ---- "-", "~", ".", ! "+", /* 40 */ "-", "*", "/", *************** *** 189,195 **** "&", "|", "^", ! "->", "int->double", "double->int", "&&", --- 194,200 ---- "&", "|", "^", ! "->", /* 50 */ "int->double", "double->int", "&&", *************** *** 199,205 **** "long->double", "integer->long", "long->integer", ! "==", "!=", "<=", "<", --- 204,210 ---- "long->double", "integer->long", "long->integer", ! "==", /* 60 */ "!=", "<=", "<", *************** *** 209,215 **** "<=p", ">p", ">=p", ! "+=", "-=", "*=", "/=", --- 214,220 ---- "<=p", ">p", ">=p", ! "+=", /* 70 */ "-=", "*=", "/=", *************** *** 219,225 **** "&=", "|=", "^=", ! "=", "& for tests", "*", "/", --- 224,230 ---- "&=", "|=", "^=", ! "=", /* 80 */ "& for tests", "*", "/", *************** *** 229,235 **** "/=", "%=", 0, ! "?", "<<", "<<=", "\\/", --- 234,240 ---- "/=", "%=", 0, ! "?", /* 90 */ "<<", "<<=", "\\/", *************** *** 236,246 **** "\\/", "/\\", "/\\", ! 0, ! "call", ! "call", ! "call", ! 0, "goto", "jump cond", "branch cond", --- 241,251 ---- "\\/", "/\\", "/\\", ! ",", ! "call1", ! "call2", ! "call", /* 100 */ ! "mcall", "goto", "jump cond", "branch cond", *************** *** 249,274 **** "ptr->integer", 0, "int->char", ! "force register", ! "", ! "", ! "", ! "", "=structure", "= (struct setup)", "/", "%", "/=", ! "%=", ! "*", /* unsigned long */ ! "/", /* unsigned long */ ! "%", /* unsigned long */ ! "*=", /* unsigned long */ ! "/=", /* unsigned long */ ! "%=", /* unsigned long */ ! "u_long->double", /* unsigned long */ ! ">>", /* unsigned long */ ! ">>=", /* unsigned long */ }; /* --- 254,279 ---- "ptr->integer", 0, "int->char", ! "force register", /* 110 */ ! "branch", ! "label", ! "nlabel", ! "rlabel", "=structure", "= (struct setup)", "/", "%", "/=", ! "%=", /* 120 */ ! "*", /* unsigned long */ ! "/", /* unsigned long */ ! "%", /* unsigned long */ ! "*=", /* unsigned long */ ! "/=", /* unsigned long */ ! "%=", /* unsigned long */ ! "u_long->double", /* unsigned long */ ! ">>", /* unsigned long */ ! ">>=", /* 129 unsigned long */ }; /*