ID Number: Q72066
6.00 6.00a | 6.00 6.00a
MS-DOS | OS/2
buglist6.00 buglist6.00a
Summary:
The Microsoft C version 6.00 and 6.00a compilers may generate bad code
for a shift operation when optimizing the code. If there is a sequence
of shift operations being performed on the same variable, the compiler
will try to maintain that variable in registers. The compiler may also
try to use the same registers to hold the shift count. The compiler
does not recognize that it needs to reload the variable from memory,
and incorrectly uses the shift count instead. This causes the result
to contain the shift count rather than the value it should have.
This problem can occur in all memory models when optimization other
than /Os or /Od is used with the optimizing compiler. The code
generated by the quick compiler (/qc) is correct in all cases.
More Information:
The following listing shows the code that was generated by the
compiler with default optimizations for the sample program below. At
the beginning of the listing, the low word of ilong is stored in CX.
To do the left shift, the compiler loads the shift count in AL,
exchanges the values in the AL and CL registers, and performs the
required shift.
array2x[i][j]= (char) (( (int) ilong & 0x0F) << 4);
*** 000053 b0 04 mov al,4
*** 000055 86 c8 xchg cl,al
*** 000057 d2 e0 shl al,cl
*** 000059 88 84 00 00 mov BYTE PTR _array2x[si],al
The compiler later assumes that CX still contains the low word of
ilong when it is going to do the left shift by two. This results in
the shift count, four, to be shifted by two, and the same value is
returned no matter what the value of ilong.
array2y[i][j]= ilong >> 4;
...
array3x[i][j]= (char) (( (int) ilong & 0x3F) << 2);
*** 00007b d0 e1 shl cl,1
*** 00007d d0 e1 shl cl,1
*** 00007f 88 8c 00 00 mov BYTE PTR _array3x[si],cl
Microsoft has confirmed this to be a problem in C versions 6.00 and
6.00a. We are researching this problem and will post new information
here as it becomes available.
Sample Code
-----------
/* Compile options needed: none
*/
long int array[4][64];
char array1x[4][64];
long int array1y[4][64];
char array2x[4][64];
long int array2y[4][64];
char array3x[4][64];
long int array3y[4][64];
void foo (int i, int j, long int ilong)
{
array[i][j]= ilong;
array1x[i][j]= (char) (( (int) ilong & 0x03) << 6);
array1y[i][j]= ilong >> 2;
array2x[i][j]= (char) (( (int) ilong & 0x0F) << 4);
array2y[i][j]= ilong >> 4;
array3x[i][j]= (char) (( (int) ilong & 0x3F) << 2);
array3y[i][j]= ilong >> 6;
}