C optimizer can generate incorrect code for "*p++ & 1"
Ken Lalonde
kwlalonde at watmath.UUCP
Fri Apr 11 15:42:42 AEST 1986
Index: lib/c2/c21.c 4.2BSD Fix
Description:
The optimizer will replace a single bit AND operation
followed by a jump with a jump-on-bit-set, that is,
bitb power-of-2,x => jbc log2(p2),x,Label
jxx Label
C2 also checks for the special case p2 == 1, and replaces
jbc $0,x,Label => jlbc x,Label
Now, bitb and jbc consider "x" to be a byte quantity,
but "jlbc" wants a longword. If "x" involves autoincrement
or autodecrement, the second optimization is wrong.
Repeat-By:
Compile this with and without the optimizer:
main()
{
register char *p = "01234";
if (*p++ & 1)
;
if (*p != '1')
printf("p = %c, should be 1\n", *p);
}
Fix:
Don't apply the jlbc replacement if autoincrement/decrement is
used. The autoid() function below is from a previous
bug fix by chris at maryland.
*** /usr/distr/4.2/usr/src/lib/c2/c21.c Tue Jun 8 23:59:06 1982
--- ./c21.c Thu Apr 10 23:48:51 1986
***************
*** 740,746
if (cp1=p->forw->code) {/* destination is not an internal label */
cp2=regs[RT3]; while (*cp2++= *cp1++);
}
! if (b==0 && (p->subop==LONG || !indexa(regs[RT2]))) {/* JLB optimization, ala BLISS */
cp2=regs[RT1]; cp1=regs[RT2]; while (*cp2++= *cp1++);
cp2=regs[RT2]; cp1=regs[RT3]; while (*cp2++= *cp1++);
*(regs[RT3])=0; p->forw->subop += JLBC-JBC;
--- 744,750 -----
if (cp1=p->forw->code) {/* destination is not an internal label */
cp2=regs[RT3]; while (*cp2++= *cp1++);
}
! if (b==0 && (p->subop==LONG || !autoid(regs[RT2]) && !indexa(regs[RT2]))) {/* JLB optimization, ala BLISS */
cp2=regs[RT1]; cp1=regs[RT2]; while (*cp2++= *cp1++);
cp2=regs[RT2]; cp1=regs[RT3]; while (*cp2++= *cp1++);
*(regs[RT3])=0; p->forw->subop += JLBC-JBC;
***************
*** 1361,1366
indexa(p) register char *p; {/* 1-> uses [r] addressing mode; 0->doesn't */
while (*p) if (*p++=='[') return(1);
return(0);
}
--- 1392,1404 -----
indexa(p) register char *p; {/* 1-> uses [r] addressing mode; 0->doesn't */
while (*p) if (*p++=='[') return(1);
+ return(0);
+ }
+
+ autoid(p) register char *p; {/* 1-> uses autoincrement/autodecrement; 0->doesn't */
+ if (*p == '-' && *(p+1) == '(') return(1);
+ while (*p) p++;
+ if (*--p == '+' && *--p == ')') return(1);
return(0);
}
More information about the Comp.bugs.4bsd.ucb-fixes
mailing list