C 6.00/6.00a May Generate Bad Code on Multiple Shifts

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;

}