This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
Bug in code generation of gcc-2.95.2
- To: gcc-bugs at gcc dot gnu dot org
- Subject: Bug in code generation of gcc-2.95.2
- From: jacob at jacob dot remcomp dot fr
- Date: Sat, 1 Jan 2000 12:32:18 +0100 (CET)
Consider the following code:
char *Picklist[8];
int func()
{
int i;
i = 0;
while (i < 7) {
Picklist[i] = Picklist[i+1];
i++;
}
return 0;
}
The code generated for this loop by gcc is:
movl $04b0940,%ecx (puts PickList in ecx)
movl $0x1,%edx (index, starts at one)
loop:
movl (%ecx,%edx,4),%eax (puts Picklist[i+1] in eax)
movl %eax,-4(%ecx,%edx) (puts eax into Picklist[i])
leal 0x1(%edx),%edi (increments edx into edi)
movl %edi,%edx (copies into edx the incremented value)
cmpl $0x6,%edx (HERE IS THE BUG!!!!!!!!!)
jle loop
Gcc is optimizing the access to the table, using a loop counter starting at
1 instead of zero. This could be quite ok, but gcc forgets to increment the
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
integer at the end of the test!!! This loop is copying
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Picklist[5] = Picklist[6]
as the LAST copy, instead of the correct
Picklist[6] = Picklist[7]
as SPECIFIED IN THE C Code!!!
If you pre-increment the loop index, then you should increment the boundary
test too, if not, as this is the case with the shown C code, the generated code
fails to copy the last element of the array.
When I replace the above loop by the equivalent:
memmove(PickList,&PickList[1],(MAXPICKLIST-1)*sizeof(char *));
PickList[MAXPICKLIST-1] = p;
Everything is OK, no bugs, no crashes.
If I do not specify any optimizations, the bug goes away of course.
This bug doesn't appear in the code snippet above, but only in certain
circumstances, i.e. when not all registers are available, etc etc.
The optimization level I used -O2.
------------------------------------------------------------------cut here
Here is a code snippet that will demonstrate the bug:
#define MAXPICKLIST 8
char *PickList[MAXPICKLIST];
int ReadOpen(char *fn, int historyflag)
{
char *p;
int i, j;
p = "Something";
i = 0;
while (i < MAXPICKLIST) {
if (PickList[i] == (char *)0) {
PickList[i] = p;
break;
}
i++;
}
if (i == MAXPICKLIST) {
release(PickList[0]);
i = 0;
/* The last assignment that this code specifies is
PickList[MAXPICKLIST-2] = PickList[MAXPICKLIST-1] or, in
numbers:
PickList[6] = PickList[7]
This is not respected in the generated code */
while (i < MAXPICKLIST - 1) {
PickList[i] = PickList[i + 1];
i++;
}
PickList[i] = p;
}
return (0);
}
---------------------------------------------------------------cut here
Compile this with
gcc -O2 -c -S test.c
You will obtain the assembler where the bug is obvious (look at the
initialization of edx to one, near the end of the function).
--
Jacob Navia Logiciels/Informatique
41 rue Maurice Ravel Tel 01 48.23.51.44
93430 Villetaneuse Fax 01 48.23.95.39
France